Merge "Use MaskableIconDrawable only in dogfood builds" into ub-launcher3-master
diff --git a/build.gradle b/build.gradle
index 00667f1..3a812a9 100644
--- a/build.gradle
+++ b/build.gradle
@@ -72,7 +72,7 @@
androidTestCompile 'com.google.dexmaker:dexmaker-mockito:1.2'
androidTestCompile 'com.android.support.test:runner:0.5'
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
- androidTestCompile 'com.android.support:support-annotations:23.2.0'
+ androidTestCompile "com.android.support:support-annotations:${SUPPORT_LIBS_VERSION}"
}
protobuf {
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a8a25af..1a09fa0 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -81,8 +81,6 @@
<dimen name="all_apps_divider_margin_vertical">8dp</dimen>
- <dimen name="all_apps_bezel_swipe_height">24dp</dimen>
-
<!-- Widget tray -->
<dimen name="widget_preview_label_vertical_padding">8dp</dimen>
<dimen name="widget_preview_label_horizontal_padding">8dp</dimen>
diff --git a/res/xml/app_target_browser.xml b/res/xml/app_target_browser.xml
deleted file mode 100644
index d7c3ed5..0000000
--- a/res/xml/app_target_browser.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 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.
--->
-
-<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
-
- <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_BROWSER;end" />
- <favorite launcher:uri="http://www.example.com/" />
-
-</resolve>
\ No newline at end of file
diff --git a/res/xml/app_target_camera.xml b/res/xml/app_target_camera.xml
deleted file mode 100644
index f65a2b1..0000000
--- a/res/xml/app_target_camera.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 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.
--->
-
-<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
-
- <favorite launcher:uri="#Intent;action=android.media.action.STILL_IMAGE_CAMERA;end" />
- <favorite launcher:uri="#Intent;action=android.intent.action.CAMERA_BUTTON;end" />
-
-</resolve>
\ No newline at end of file
diff --git a/res/xml/app_target_email.xml b/res/xml/app_target_email.xml
deleted file mode 100644
index 44f0a40..0000000
--- a/res/xml/app_target_email.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 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.
--->
-
-<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
-
- <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_EMAIL;end" />
- <favorite launcher:uri="mailto:" />
-
-</resolve>
\ No newline at end of file
diff --git a/res/xml/app_target_gallery.xml b/res/xml/app_target_gallery.xml
deleted file mode 100644
index c9d3492..0000000
--- a/res/xml/app_target_gallery.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 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.
--->
-
-<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
-
- <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_GALLERY;end" />
- <favorite launcher:uri="#Intent;type=images/*;end" />
-
-</resolve>
\ No newline at end of file
diff --git a/res/xml/app_target_messenger.xml b/res/xml/app_target_messenger.xml
deleted file mode 100644
index 278eb5c..0000000
--- a/res/xml/app_target_messenger.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 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.
--->
-
-<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
-
- <favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MESSAGING;end" />
- <favorite launcher:uri="sms:" />
- <favorite launcher:uri="smsto:" />
- <favorite launcher:uri="mms:" />
- <favorite launcher:uri="mmsto:" />
-
-</resolve>
\ No newline at end of file
diff --git a/res/xml/app_target_phone.xml b/res/xml/app_target_phone.xml
deleted file mode 100644
index 5d6ca31..0000000
--- a/res/xml/app_target_phone.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2015 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.
--->
-
-<resolve xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3" >
-
- <favorite launcher:uri="#Intent;action=android.intent.action.DIAL;end" />
- <favorite launcher:uri="tel:123" />
- <favorite launcher:uri="#Intent;action=android.intent.action.CALL_BUTTON;end" />
-
-</resolve>
\ No newline at end of file
diff --git a/src/com/android/launcher3/AllAppsList.java b/src/com/android/launcher3/AllAppsList.java
index 34a44fc..9cce9b1 100644
--- a/src/com/android/launcher3/AllAppsList.java
+++ b/src/com/android/launcher3/AllAppsList.java
@@ -18,9 +18,9 @@
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.LauncherActivityInfo;
import android.os.UserHandle;
-import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.ItemInfoMatcher;
@@ -65,13 +65,15 @@
*
* If the app is already in the list, doesn't add it.
*/
- public void add(AppInfo info) {
+ public void add(AppInfo info, LauncherActivityInfo activityInfo) {
if (!mAppFilter.shouldShowApp(info.componentName)) {
return;
}
if (findActivity(data, info.componentName, info.user)) {
return;
}
+ mIconCache.getTitleAndIcon(info, activityInfo, true /* useLowResIcon */);
+
data.add(info);
added.add(info);
}
@@ -97,11 +99,11 @@
*/
public void addPackage(Context context, String packageName, UserHandle user) {
final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
- final List<LauncherActivityInfoCompat> matches = launcherApps.getActivityList(packageName,
+ final List<LauncherActivityInfo> matches = launcherApps.getActivityList(packageName,
user);
- for (LauncherActivityInfoCompat info : matches) {
- add(new AppInfo(context, info, user, mIconCache));
+ for (LauncherActivityInfo info : matches) {
+ add(new AppInfo(context, info, user), info);
}
}
@@ -148,7 +150,7 @@
*/
public void updatePackage(Context context, String packageName, UserHandle user) {
final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(context);
- final List<LauncherActivityInfoCompat> matches = launcherApps.getActivityList(packageName,
+ final List<LauncherActivityInfo> matches = launcherApps.getActivityList(packageName,
user);
if (matches.size() > 0) {
// Find disabled/removed activities and remove them from data and add them
@@ -166,12 +168,12 @@
// Find enabled activities and add them to the adapter
// Also updates existing activities with new labels/icons
- for (final LauncherActivityInfoCompat info : matches) {
+ for (final LauncherActivityInfo info : matches) {
AppInfo applicationInfo = findApplicationInfoLocked(
info.getComponentName().getPackageName(), user,
info.getComponentName().getClassName());
if (applicationInfo == null) {
- add(new AppInfo(context, info, user, mIconCache));
+ add(new AppInfo(context, info, user), info);
} else {
mIconCache.getTitleAndIcon(applicationInfo, info, true /* useLowResIcon */);
modified.add(applicationInfo);
@@ -195,9 +197,9 @@
/**
* Returns whether <em>apps</em> contains <em>component</em>.
*/
- private static boolean findActivity(List<LauncherActivityInfoCompat> apps,
+ private static boolean findActivity(List<LauncherActivityInfo> apps,
ComponentName component) {
- for (LauncherActivityInfoCompat info : apps) {
+ for (LauncherActivityInfo info : apps) {
if (info.getComponentName().equals(component)) {
return true;
}
diff --git a/src/com/android/launcher3/AppInfo.java b/src/com/android/launcher3/AppInfo.java
index 9c9dcc5..6bec997 100644
--- a/src/com/android/launcher3/AppInfo.java
+++ b/src/com/android/launcher3/AppInfo.java
@@ -19,10 +19,10 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.LauncherActivityInfo;
import android.os.UserHandle;
import android.util.Log;
-import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageManagerHelper;
@@ -58,19 +58,12 @@
/**
* Must not hold the Context.
*/
- public AppInfo(Context context, LauncherActivityInfoCompat info, UserHandle user,
- IconCache iconCache) {
- this(context, info, user, iconCache,
- UserManagerCompat.getInstance(context).isQuietModeEnabled(user));
+ public AppInfo(Context context, LauncherActivityInfo info, UserHandle user) {
+ this(context, info, user, UserManagerCompat.getInstance(context).isQuietModeEnabled(user));
}
- public AppInfo(Context context, LauncherActivityInfoCompat info, UserHandle user,
- IconCache iconCache, boolean quietModeEnabled) {
- this(context, info, user, iconCache, quietModeEnabled, true /* useLowResIcon */);
- }
-
- public AppInfo(Context context, LauncherActivityInfoCompat info, UserHandle user,
- IconCache iconCache, boolean quietModeEnabled, boolean useLowResIcon) {
+ public AppInfo(Context context, LauncherActivityInfo info, UserHandle user,
+ boolean quietModeEnabled) {
this.componentName = info.getComponentName();
this.container = ItemInfo.NO_ID;
this.user = user;
@@ -82,7 +75,6 @@
}
intent = makeLaunchIntent(context, info, user);
- iconCache.getTitleAndIcon(this, info, useLowResIcon);
}
public AppInfo(AppInfo info) {
@@ -118,7 +110,7 @@
return new ComponentKey(componentName, user);
}
- public static Intent makeLaunchIntent(Context context, LauncherActivityInfoCompat info,
+ public static Intent makeLaunchIntent(Context context, LauncherActivityInfo info,
UserHandle user) {
long serialNumber = UserManagerCompat.getInstance(context).getSerialNumberForUser(user);
return new Intent(Intent.ACTION_MAIN)
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index f879216..1a405f9 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -212,6 +212,23 @@
lp.height = mTempRange1.size();
resizeWidgetIfNeeded(false);
+
+ // When the widget resizes in multi-window mode, the translation value changes to maintain
+ // a center fit. These overrides ensure the resize frame always aligns with the widget view.
+ getSnappedRectRelativeToDragLayer(sTmpRect);
+ if (mLeftBorderActive) {
+ lp.width = sTmpRect.width() + sTmpRect.left - lp.x;
+ }
+ if (mTopBorderActive) {
+ lp.height = sTmpRect.height() + sTmpRect.top - lp.y;
+ }
+ if (mRightBorderActive) {
+ lp.x = sTmpRect.left;
+ }
+ if (mBottomBorderActive) {
+ lp.y = sTmpRect.top;
+ }
+
requestLayout();
}
@@ -303,7 +320,7 @@
public static Rect getWidgetSizeRanges(Context context, int spanX, int spanY, Rect rect) {
if (sCellSize == null) {
- InvariantDeviceProfile inv = LauncherAppState.getInstance().getInvariantDeviceProfile();
+ InvariantDeviceProfile inv = LauncherAppState.getIDP(context);
// Initiate cell sizes.
sCellSize = new Point[2];
@@ -340,8 +357,8 @@
int xThreshold = mCellLayout.getCellWidth();
int yThreshold = mCellLayout.getCellHeight();
- mDeltaXAddOn = mRunningHInc * xThreshold;
- mDeltaYAddOn = mRunningVInc * yThreshold;
+ mDeltaXAddOn = mRunningHInc * xThreshold;
+ mDeltaYAddOn = mRunningVInc * yThreshold;
mDeltaX = 0;
mDeltaY = 0;
@@ -353,18 +370,35 @@
});
}
- public void snapToWidget(boolean animate) {
+ /**
+ * Returns the rect of this view when the frame is snapped around the widget, with the bounds
+ * relative to the {@link DragLayer}.
+ */
+ private void getSnappedRectRelativeToDragLayer(Rect out) {
float scale = mWidgetView.getScaleToFit();
- mDragLayer.getViewRectRelativeToSelf(mWidgetView, sTmpRect);
+ mDragLayer.getViewRectRelativeToSelf(mWidgetView, out);
- int newWidth = 2 * mBackgroundPadding
- + (int) (scale * (sTmpRect.width() - mWidgetPadding.left - mWidgetPadding.right));
- int newHeight = 2 * mBackgroundPadding
- + (int) (scale * (sTmpRect.height() - mWidgetPadding.top - mWidgetPadding.bottom));
+ int width = 2 * mBackgroundPadding
+ + (int) (scale * (out.width() - mWidgetPadding.left - mWidgetPadding.right));
+ int height = 2 * mBackgroundPadding
+ + (int) (scale * (out.height() - mWidgetPadding.top - mWidgetPadding.bottom));
- int newX = (int) (sTmpRect.left - mBackgroundPadding + scale * mWidgetPadding.left);
- int newY = (int) (sTmpRect.top - mBackgroundPadding + scale * mWidgetPadding.top);
+ int x = (int) (out.left - mBackgroundPadding + scale * mWidgetPadding.left);
+ int y = (int) (out.top - mBackgroundPadding + scale * mWidgetPadding.top);
+
+ out.left = x;
+ out.top = y;
+ out.right = out.left + width;
+ out.bottom = out.top + height;
+ }
+
+ public void snapToWidget(boolean animate) {
+ getSnappedRectRelativeToDragLayer(sTmpRect);
+ int newWidth = sTmpRect.width();
+ int newHeight = sTmpRect.height();
+ int newX = sTmpRect.left;
+ int newY = sTmpRect.top;
// We need to make sure the frame's touchable regions lie fully within the bounds of the
// DragLayer. We allow the actual handles to be clipped, but we shift the touch regions
diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
index c5b3104..c6f1c48 100644
--- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
+++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
@@ -5,13 +5,13 @@
import android.appwidget.AppWidgetProviderInfo;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.util.Log;
import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.util.ContentWriter;
public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
@@ -50,14 +50,13 @@
state = LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY;
}
- ContentValues values = new ContentValues();
- values.put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i]);
- values.put(LauncherSettings.Favorites.RESTORED, state);
-
String[] widgetIdParams = new String[] { Integer.toString(oldWidgetIds[i]) };
+ int result = new ContentWriter(context, new ContentWriter.CommitParams(
+ "appWidgetId=? and (restored & 1) = 1", widgetIdParams))
+ .put(LauncherSettings.Favorites.APPWIDGET_ID, newWidgetIds[i])
+ .put(LauncherSettings.Favorites.RESTORED, state)
+ .commit();
- int result = cr.update(Favorites.CONTENT_URI, values,
- "appWidgetId=? and (restored & 1) = 1", widgetIdParams);
if (result == 0) {
Cursor cursor = cr.query(Favorites.CONTENT_URI,
new String[] {Favorites.APPWIDGET_ID},
diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java
index 2a4212a..2e017df 100644
--- a/src/com/android/launcher3/AutoInstallsLayout.java
+++ b/src/com/android/launcher3/AutoInstallsLayout.java
@@ -79,7 +79,7 @@
static AutoInstallsLayout get(Context context, String pkg, Resources targetRes,
AppWidgetHost appWidgetHost, LayoutParserCallback callback) {
- InvariantDeviceProfile grid = LauncherAppState.getInstance().getInvariantDeviceProfile();
+ InvariantDeviceProfile grid = LauncherAppState.getIDP(context);
// Try with grid size and hotseat count
String layoutName = String.format(Locale.ENGLISH, FORMATTED_LAYOUT_RES_WITH_HOSTEAT,
@@ -182,7 +182,7 @@
mSourceRes = res;
mLayoutId = layoutId;
- mIdp = LauncherAppState.getInstance().getInvariantDeviceProfile();
+ mIdp = LauncherAppState.getIDP(context);
mRowCount = mIdp.numRows;
mColumnCount = mIdp.numColumns;
}
diff --git a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
index 40c5ed6..4fecc3d 100644
--- a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
+++ b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java
@@ -28,6 +28,8 @@
import android.view.ViewConfiguration;
import android.widget.TextView;
+import com.android.launcher3.config.FeatureFlags;
+
/**
* The track and scrollbar that shows when you scroll the list.
*/
@@ -198,6 +200,11 @@
case MotionEvent.ACTION_DOWN:
if (isNearThumb(downX, downY)) {
mTouchOffsetY = downY - mThumbOffsetY;
+ } else if (FeatureFlags.LAUNCHER3_DIRECT_SCROLL
+ && mRv.supportsFastScrolling()
+ && isNearScrollBar(downX)) {
+ calcTouchOffsetAndPrepToFastScroll(downY, lastY);
+ updateFastScrollSectionNameAndThumbOffset(lastY, y);
}
break;
case MotionEvent.ACTION_MOVE:
@@ -207,28 +214,10 @@
if (!mIsDragging && !mIgnoreDragGesture && mRv.supportsFastScrolling() &&
isNearThumb(downX, lastY) &&
Math.abs(y - downY) > config.getScaledTouchSlop()) {
- mRv.getParent().requestDisallowInterceptTouchEvent(true);
- mIsDragging = true;
- if (mCanThumbDetach) {
- mIsThumbDetached = true;
- }
- mTouchOffsetY += (lastY - downY);
- animatePopupVisibility(true);
- showActiveScrollbar(true);
+ calcTouchOffsetAndPrepToFastScroll(downY, lastY);
}
if (mIsDragging) {
- // Update the fastscroller section name at this touch position
- int bottom = mRv.getScrollbarTrackHeight() - mThumbHeight;
- float boundedY = (float) Math.max(0, Math.min(bottom, y - mTouchOffsetY));
- String sectionName = mRv.scrollToPositionAtProgress(boundedY / bottom);
- if (!sectionName.equals(mPopupSectionName)) {
- mPopupSectionName = sectionName;
- mPopupView.setText(sectionName);
- }
- animatePopupVisibility(!sectionName.isEmpty());
- updatePopupY(lastY);
- mLastTouchY = boundedY;
- setThumbOffsetY((int) mLastTouchY);
+ updateFastScrollSectionNameAndThumbOffset(lastY, y);
}
break;
case MotionEvent.ACTION_UP:
@@ -245,6 +234,32 @@
}
}
+ private void calcTouchOffsetAndPrepToFastScroll(int downY, int lastY) {
+ mRv.getParent().requestDisallowInterceptTouchEvent(true);
+ mIsDragging = true;
+ if (mCanThumbDetach) {
+ mIsThumbDetached = true;
+ }
+ mTouchOffsetY += (lastY - downY);
+ animatePopupVisibility(true);
+ showActiveScrollbar(true);
+ }
+
+ private void updateFastScrollSectionNameAndThumbOffset(int lastY, int y) {
+ // Update the fastscroller section name at this touch position
+ int bottom = mRv.getScrollbarTrackHeight() - mThumbHeight;
+ float boundedY = (float) Math.max(0, Math.min(bottom, y - mTouchOffsetY));
+ String sectionName = mRv.scrollToPositionAtProgress(boundedY / bottom);
+ if (!sectionName.equals(mPopupSectionName)) {
+ mPopupSectionName = sectionName;
+ mPopupView.setText(sectionName);
+ }
+ animatePopupVisibility(!sectionName.isEmpty());
+ updatePopupY(lastY);
+ mLastTouchY = boundedY;
+ setThumbOffsetY((int) mLastTouchY);
+ }
+
public void draw(Canvas canvas) {
if (mThumbOffsetY < 0) {
return;
@@ -277,7 +292,7 @@
}
/**
- * Returns whether the specified points are near the scroll bar bounds.
+ * Returns whether the specified point is inside the thumb bounds.
*/
public boolean isNearThumb(int x, int y) {
int left = getDrawLeft();
@@ -286,6 +301,14 @@
return mTmpRect.contains(x, y);
}
+ /**
+ * Returns whether the specified x position is near the scroll bar.
+ */
+ public boolean isNearScrollBar(int x) {
+ int left = getDrawLeft();
+ return x >= left && x <= left + mMaxWidth;
+ }
+
private void animatePopupVisibility(boolean visible) {
if (mPopupVisible != visible) {
mPopupVisible = visible;
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 5e9e7e2..32c3ac8 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -38,6 +38,7 @@
import android.widget.TextView;
import com.android.launcher3.IconCache.IconLoadRequest;
+import com.android.launcher3.IconCache.ItemInfoUpdateReceiver;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.graphics.HolographicOutlineHelper;
@@ -51,7 +52,7 @@
* too aggressive.
*/
public class BubbleTextView extends TextView
- implements BaseRecyclerViewFastScrollBar.FastScrollFocusableView {
+ implements BaseRecyclerViewFastScrollBar.FastScrollFocusableView, ItemInfoUpdateReceiver {
private static SparseArray<Theme> sPreloaderThemes = new SparseArray<Theme>(2);
@@ -540,7 +541,8 @@
/**
* Applies the item info if it is same as what the view is pointing to currently.
*/
- public void reapplyItemInfo(final ItemInfo info) {
+ @Override
+ public void reapplyItemInfo(ItemInfoWithIcon info) {
if (getTag() == info) {
FastBitmapDrawable.State prevState = FastBitmapDrawable.State.NORMAL;
if (mIcon instanceof FastBitmapDrawable) {
@@ -582,22 +584,10 @@
mIconLoadRequest.cancel();
mIconLoadRequest = null;
}
- if (getTag() instanceof AppInfo) {
- AppInfo info = (AppInfo) getTag();
+ if (getTag() instanceof ItemInfoWithIcon) {
+ ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
if (info.usingLowResIcon) {
- mIconLoadRequest = LauncherAppState.getInstance().getIconCache()
- .updateIconInBackground(BubbleTextView.this, info);
- }
- } else if (getTag() instanceof ShortcutInfo) {
- ShortcutInfo info = (ShortcutInfo) getTag();
- if (info.usingLowResIcon) {
- mIconLoadRequest = LauncherAppState.getInstance().getIconCache()
- .updateIconInBackground(BubbleTextView.this, info);
- }
- } else if (getTag() instanceof PackageItemInfo) {
- PackageItemInfo info = (PackageItemInfo) getTag();
- if (info.usingLowResIcon) {
- mIconLoadRequest = LauncherAppState.getInstance().getIconCache()
+ mIconLoadRequest = LauncherAppState.getInstance(getContext()).getIconCache()
.updateIconInBackground(BubbleTextView.this, info);
}
}
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 70c8739..da12e67 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -2096,6 +2096,7 @@
a.cancel();
}
+ setInitialAnimationValues(true);
a = new LauncherViewPropertyAnimator(child)
.scaleX(initScale)
.scaleY(initScale)
diff --git a/src/com/android/launcher3/CommonAppTypeParser.java b/src/com/android/launcher3/CommonAppTypeParser.java
deleted file mode 100644
index c2bd883..0000000
--- a/src/com/android/launcher3/CommonAppTypeParser.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.XmlResourceParser;
-import android.database.sqlite.SQLiteDatabase;
-import android.util.Log;
-
-import com.android.launcher3.AutoInstallsLayout.LayoutParserCallback;
-import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.util.Thunk;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-
-/**
- * A class that parses content values corresponding to some common app types.
- */
-public class CommonAppTypeParser implements LayoutParserCallback {
- private static final String TAG = "CommonAppTypeParser";
-
- // Including TARGET_NONE
- public static final int SUPPORTED_TYPE_COUNT = 7;
-
- private static final int RESTORE_FLAG_BIT_SHIFT = 4;
-
- public static final int TARGET_PHONE = 1;
- public static final int TARGET_MESSENGER = 2;
- public static final int TARGET_EMAIL = 3;
- public static final int TARGET_BROWSER = 4;
- public static final int TARGET_GALLERY = 5;
- public static final int TARGET_CAMERA = 6;
-
- private final long mItemId;
- @Thunk final int mResId;
- @Thunk final Context mContext;
-
- ContentValues parsedValues;
- Intent parsedIntent;
- String parsedTitle;
-
- public CommonAppTypeParser(long itemId, int itemType, Context context) {
- mItemId = itemId;
- mContext = context;
- mResId = getResourceForItemType(itemType);
- }
-
- @Override
- public long generateNewItemId() {
- return mItemId;
- }
-
- @Override
- public long insertAndCheck(SQLiteDatabase db, ContentValues values) {
- parsedValues = values;
-
- // Remove unwanted values
- values.put(Favorites.ICON_PACKAGE, (String) null);
- values.put(Favorites.ICON_RESOURCE, (String) null);
- values.put(Favorites.ICON, (byte[]) null);
- return 1;
- }
-
- /**
- * Tries to find a suitable app to the provided app type.
- */
- public boolean findDefaultApp() {
- if (mResId == 0) {
- return false;
- }
-
- parsedIntent = null;
- parsedValues = null;
- new MyLayoutParser().parseValues();
- return (parsedValues != null) && (parsedIntent != null);
- }
-
- private class MyLayoutParser extends DefaultLayoutParser {
-
- public MyLayoutParser() {
- super(CommonAppTypeParser.this.mContext, null, CommonAppTypeParser.this,
- CommonAppTypeParser.this.mContext.getResources(), mResId, TAG_RESOLVE);
- }
-
- @Override
- protected long addShortcut(String title, Intent intent, int type) {
- if (type == Favorites.ITEM_TYPE_APPLICATION) {
- parsedIntent = intent;
- parsedTitle = title;
- }
- return super.addShortcut(title, intent, type);
- }
-
- public void parseValues() {
- XmlResourceParser parser = mSourceRes.getXml(mLayoutId);
- try {
- beginDocument(parser, mRootTag);
- new ResolveParser().parseAndAdd(parser);
- } catch (IOException | XmlPullParserException e) {
- Log.e(TAG, "Unable to parse default app info", e);
- }
- parser.close();
- }
- }
-
- public static int getResourceForItemType(int type) {
- switch (type) {
- case TARGET_PHONE:
- return R.xml.app_target_phone;
-
- case TARGET_MESSENGER:
- return R.xml.app_target_messenger;
-
- case TARGET_EMAIL:
- return R.xml.app_target_email;
-
- case TARGET_BROWSER:
- return R.xml.app_target_browser;
-
- case TARGET_GALLERY:
- return R.xml.app_target_gallery;
-
- case TARGET_CAMERA:
- return R.xml.app_target_camera;
-
- default:
- return 0;
- }
- }
-
- public static int encodeItemTypeToFlag(int itemType) {
- return itemType << RESTORE_FLAG_BIT_SHIFT;
- }
-
- public static int decodeItemTypeFromFlag(int flag) {
- return (flag & ShortcutInfo.FLAG_RESTORED_APP_TYPE) >> RESTORE_FLAG_BIT_SHIFT;
- }
-
-}
diff --git a/src/com/android/launcher3/DefaultLayoutParser.java b/src/com/android/launcher3/DefaultLayoutParser.java
index ef28d1e..05911ab 100644
--- a/src/com/android/launcher3/DefaultLayoutParser.java
+++ b/src/com/android/launcher3/DefaultLayoutParser.java
@@ -54,11 +54,6 @@
super(context, appWidgetHost, callback, sourceRes, layoutId, TAG_FAVORITES);
}
- public DefaultLayoutParser(Context context, AppWidgetHost appWidgetHost,
- LayoutParserCallback callback, Resources sourceRes, int layoutId, String rootTag) {
- super(context, appWidgetHost, callback, sourceRes, layoutId, rootTag);
- }
-
@Override
protected HashMap<String, TagParser> getFolderElementsMap() {
return getFolderElementsMap(mSourceRes);
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index b22cb7c..6535d65 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -45,13 +46,13 @@
import android.text.TextUtils;
import android.util.Log;
-import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.Provider;
import com.android.launcher3.util.SQLiteCacheHelper;
import com.android.launcher3.util.Thunk;
@@ -188,7 +189,7 @@
return getFullResDefaultActivityIcon();
}
- private Bitmap makeDefaultIcon(UserHandle user) {
+ protected Bitmap makeDefaultIcon(UserHandle user) {
Drawable unbadged = getFullResDefaultActivityIcon();
return LauncherIcons.createBadgedIconBitmap(unbadged, user, mContext);
}
@@ -225,7 +226,7 @@
PackageInfo info = mPackageManager.getPackageInfo(packageName,
PackageManager.GET_UNINSTALLED_PACKAGES);
long userSerial = mUserManager.getSerialNumberForUser(user);
- for (LauncherActivityInfoCompat app : mLauncherApps.getActivityList(packageName, user)) {
+ for (LauncherActivityInfo app : mLauncherApps.getActivityList(packageName, user)) {
addIconToDBAndMemCache(app, info, userSerial, false /*replace existing*/);
}
} catch (NameNotFoundException e) {
@@ -252,7 +253,7 @@
mIconProvider.updateSystemStateString();
for (UserHandle user : mUserManager.getUserProfiles()) {
// Query for the set of apps
- final List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);
+ final List<LauncherActivityInfo> 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()) {
@@ -271,7 +272,7 @@
* the DB and are updated.
* @return The set of packages for which icons have updated.
*/
- private void updateDBIcons(UserHandle user, List<LauncherActivityInfoCompat> apps,
+ private void updateDBIcons(UserHandle user, List<LauncherActivityInfo> apps,
Set<String> ignorePackages) {
long userSerial = mUserManager.getSerialNumberForUser(user);
PackageManager pm = mContext.getPackageManager();
@@ -280,13 +281,13 @@
pkgInfoMap.put(info.packageName, info);
}
- HashMap<ComponentName, LauncherActivityInfoCompat> componentMap = new HashMap<>();
- for (LauncherActivityInfoCompat app : apps) {
+ HashMap<ComponentName, LauncherActivityInfo> componentMap = new HashMap<>();
+ for (LauncherActivityInfo app : apps) {
componentMap.put(app.getComponentName(), app);
}
HashSet<Integer> itemsToRemove = new HashSet<Integer>();
- Stack<LauncherActivityInfoCompat> appsToUpdate = new Stack<>();
+ Stack<LauncherActivityInfo> appsToUpdate = new Stack<>();
Cursor c = null;
try {
@@ -321,7 +322,7 @@
long updateTime = c.getLong(indexLastUpdate);
int version = c.getInt(indexVersion);
- LauncherActivityInfoCompat app = componentMap.remove(component);
+ LauncherActivityInfo app = componentMap.remove(component);
if (version == info.versionCode && updateTime == info.lastUpdateTime &&
TextUtils.equals(c.getString(systemStateIndex),
mIconProvider.getIconSystemState(info.packageName))) {
@@ -349,7 +350,7 @@
// Insert remaining apps.
if (!componentMap.isEmpty() || !appsToUpdate.isEmpty()) {
- Stack<LauncherActivityInfoCompat> appsToAdd = new Stack<>();
+ Stack<LauncherActivityInfo> appsToAdd = new Stack<>();
appsToAdd.addAll(componentMap.values());
new SerializedIconUpdateTask(userSerial, pkgInfoMap,
appsToAdd, appsToUpdate).scheduleNext();
@@ -362,7 +363,7 @@
* the memory. This is useful then the previous bitmap was created using
* old data.
*/
- @Thunk synchronized void addIconToDBAndMemCache(LauncherActivityInfoCompat app,
+ @Thunk synchronized void addIconToDBAndMemCache(LauncherActivityInfo app,
PackageInfo info, long userSerial, boolean replaceExisting) {
final ComponentKey key = new ComponentKey(app.getComponentName(), app.getUser());
CacheEntry entry = null;
@@ -406,13 +407,14 @@
* Fetches high-res icon for the provided ItemInfo and updates the caller when done.
* @return a request ID that can be used to cancel the request.
*/
- public IconLoadRequest updateIconInBackground(final BubbleTextView caller, final ItemInfo info) {
+ public IconLoadRequest updateIconInBackground(final ItemInfoUpdateReceiver caller,
+ final ItemInfoWithIcon info) {
Runnable request = new Runnable() {
@Override
public void run() {
if (info instanceof AppInfo || info instanceof ShortcutInfo) {
- getTitleAndIcon((ItemInfoWithIcon) info, false);
+ getTitleAndIcon(info, false);
} else if (info instanceof PackageItemInfo) {
getTitleAndIconForApp((PackageItemInfo) info, false);
}
@@ -430,25 +432,11 @@
}
/**
- * Returns a high res icon for the given intent and user
- */
- public synchronized Bitmap getIcon(Intent intent, UserHandle user) {
- ComponentName component = intent.getComponent();
- // null info means not installed, but if we have a component from the intent then
- // we should still look in the cache for restored app icons.
- if (component == null) {
- return getDefaultIcon(user);
- }
- return cacheLocked(component, new ActivityInfoProvider(intent, user),
- user, true, false /* useLowRes */).icon;
- }
-
- /**
* Updates {@param application} only if a valid entry is found.
*/
public synchronized void updateTitleAndIcon(AppInfo application) {
CacheEntry entry = cacheLocked(application.componentName,
- Provider.<LauncherActivityInfoCompat>of(null),
+ Provider.<LauncherActivityInfo>of(null),
application.user, false, application.usingLowResIcon);
if (entry.icon != null && !isDefaultIcon(entry.icon, application.user)) {
applyCacheEntry(entry, application);
@@ -459,7 +447,7 @@
* Fill in {@param info} with the icon and label for {@param activityInfo}
*/
public synchronized void getTitleAndIcon(ItemInfoWithIcon info,
- LauncherActivityInfoCompat activityInfo, boolean useLowResIcon) {
+ LauncherActivityInfo activityInfo, boolean useLowResIcon) {
// If we already have activity info, no need to use package icon
getTitleAndIcon(info, Provider.of(activityInfo), false, useLowResIcon);
}
@@ -487,7 +475,7 @@
*/
private synchronized void getTitleAndIcon(
@NonNull ItemInfoWithIcon infoInOut,
- @NonNull Provider<LauncherActivityInfoCompat> activityInfoProvider,
+ @NonNull Provider<LauncherActivityInfo> activityInfoProvider,
boolean usePkgIcon, boolean useLowResIcon) {
CacheEntry entry = cacheLocked(infoInOut.getTargetComponent(), activityInfoProvider,
infoInOut.user, usePkgIcon, useLowResIcon);
@@ -528,8 +516,9 @@
*/
protected CacheEntry cacheLocked(
@NonNull ComponentName componentName,
- @NonNull Provider<LauncherActivityInfoCompat> infoProfider,
+ @NonNull Provider<LauncherActivityInfo> infoProvider,
UserHandle user, boolean usePackageIcon, boolean useLowResIcon) {
+ Preconditions.assertWorkerThread();
ComponentKey cacheKey = new ComponentKey(componentName, user);
CacheEntry entry = mCache.get(cacheKey);
if (entry == null || (entry.isLowResIcon && !useLowResIcon)) {
@@ -537,11 +526,11 @@
mCache.put(cacheKey, entry);
// Check the DB first.
- LauncherActivityInfoCompat info = null;
+ LauncherActivityInfo info = null;
boolean providerFetchedOnce = false;
if (!getEntryFromDB(cacheKey, entry, useLowResIcon) || DEBUG_IGNORE_CACHE) {
- info = infoProfider.get();
+ info = infoProvider.get();
providerFetchedOnce = true;
if (info != null) {
@@ -570,7 +559,7 @@
if (TextUtils.isEmpty(entry.title)) {
if (info == null && !providerFetchedOnce) {
- info = infoProfider.get();
+ info = infoProvider.get();
providerFetchedOnce = true;
}
if (info != null) {
@@ -617,6 +606,7 @@
*/
private CacheEntry getEntryForPackageLocked(String packageName, UserHandle user,
boolean useLowResIcon) {
+ Preconditions.assertWorkerThread();
ComponentKey cacheKey = getPackageKey(packageName, user);
CacheEntry entry = mCache.get(cacheKey);
@@ -714,19 +704,19 @@
/**
* 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
+ * LauncherActivityInfo list. Items are updated/added one at a time, so that the
* worker thread doesn't get blocked.
*/
@Thunk 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 Stack<LauncherActivityInfo> mAppsToAdd;
+ private final Stack<LauncherActivityInfo> mAppsToUpdate;
private final HashSet<String> mUpdatedPackages = new HashSet<String>();
@Thunk SerializedIconUpdateTask(long userSerial, HashMap<String, PackageInfo> pkgInfoMap,
- Stack<LauncherActivityInfoCompat> appsToAdd,
- Stack<LauncherActivityInfoCompat> appsToUpdate) {
+ Stack<LauncherActivityInfo> appsToAdd,
+ Stack<LauncherActivityInfo> appsToUpdate) {
mUserSerial = userSerial;
mPkgInfoMap = pkgInfoMap;
mAppsToAdd = appsToAdd;
@@ -736,7 +726,7 @@
@Override
public void run() {
if (!mAppsToUpdate.isEmpty()) {
- LauncherActivityInfoCompat app = mAppsToUpdate.pop();
+ LauncherActivityInfo app = mAppsToUpdate.pop();
String pkg = app.getComponentName().getPackageName();
PackageInfo info = mPkgInfoMap.get(pkg);
addIconToDBAndMemCache(app, info, mUserSerial, true /*replace existing*/);
@@ -744,14 +734,14 @@
if (mAppsToUpdate.isEmpty() && !mUpdatedPackages.isEmpty()) {
// No more app to update. Notify model.
- LauncherAppState.getInstance().getModel().onPackageIconsUpdated(
+ LauncherAppState.getInstance(mContext).getModel().onPackageIconsUpdated(
mUpdatedPackages, mUserManager.getUserForSerialNumber(mUserSerial));
}
// Let it run one more time.
scheduleNext();
} else if (!mAppsToAdd.isEmpty()) {
- LauncherActivityInfoCompat app = mAppsToAdd.pop();
+ LauncherActivityInfo app = mAppsToAdd.pop();
PackageInfo info = mPkgInfoMap.get(app.getComponentName().getPackageName());
// We do not check the mPkgInfoMap when generating the mAppsToAdd. Although every
// app should have package info, this is not guaranteed by the api
@@ -853,7 +843,7 @@
}
}
- private class ActivityInfoProvider extends Provider<LauncherActivityInfoCompat> {
+ private class ActivityInfoProvider extends Provider<LauncherActivityInfo> {
private final Intent mIntent;
private final UserHandle mUser;
@@ -864,8 +854,16 @@
}
@Override
- public LauncherActivityInfoCompat get() {
+ public LauncherActivityInfo get() {
return mLauncherApps.resolveActivity(mIntent, mUser);
}
}
+
+ /**
+ * Interface for receiving itemInfo with high-res icon.
+ */
+ public interface ItemInfoUpdateReceiver {
+
+ void reapplyItemInfo(ItemInfoWithIcon info);
+ }
}
diff --git a/src/com/android/launcher3/IconProvider.java b/src/com/android/launcher3/IconProvider.java
index 005bbaa..a5d3990 100644
--- a/src/com/android/launcher3/IconProvider.java
+++ b/src/com/android/launcher3/IconProvider.java
@@ -1,9 +1,8 @@
package com.android.launcher3;
+import android.content.pm.LauncherActivityInfo;
import android.graphics.drawable.Drawable;
-import com.android.launcher3.compat.LauncherActivityInfoCompat;
-
import java.util.Locale;
public class IconProvider {
@@ -26,7 +25,7 @@
}
- public Drawable getIcon(LauncherActivityInfoCompat info, int iconDpi) {
+ public Drawable getIcon(LauncherActivityInfo info, int iconDpi) {
return info.getIcon(iconDpi);
}
}
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index df2deb8..ad10523 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -23,18 +23,21 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
+import android.content.pm.LauncherActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.os.Looper;
+import android.os.Parcelable;
import android.os.Process;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
-import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.shortcuts.ShortcutKey;
@@ -238,7 +241,7 @@
private static void queuePendingShortcutInfo(PendingInstallShortcutInfo info, Context context) {
// Queue the item up for adding if launcher has not loaded properly yet
- LauncherAppState app = LauncherAppState.getInstance();
+ LauncherAppState app = LauncherAppState.getInstance(context);
boolean launcherNotLoaded = app.getModel().getCallback() == null;
addToInstallQueue(Utilities.getPrefs(context), info);
@@ -258,7 +261,7 @@
static void flushInstallQueue(Context context) {
ArrayList<PendingInstallShortcutInfo> items = getAndClearInstallQueue(context);
if (!items.isEmpty()) {
- LauncherAppState.getInstance().getModel().addAndBindAddedWorkspaceItems(
+ LauncherAppState.getInstance(context).getModel().addAndBindAddedWorkspaceItems(
new LazyShortcutsProvider(context.getApplicationContext(), items));
}
}
@@ -282,7 +285,7 @@
private static class PendingInstallShortcutInfo {
- final LauncherActivityInfoCompat activityInfo;
+ final LauncherActivityInfo activityInfo;
final ShortcutInfoCompat shortcutInfo;
final AppWidgetProviderInfo providerInfo;
@@ -312,7 +315,7 @@
/**
* Initializes a PendingInstallShortcutInfo to represent a launcher target.
*/
- public PendingInstallShortcutInfo(LauncherActivityInfoCompat info, Context context) {
+ public PendingInstallShortcutInfo(LauncherActivityInfo info, Context context) {
activityInfo = info;
shortcutInfo = null;
providerInfo = null;
@@ -434,10 +437,25 @@
public ItemInfo getItemInfo() {
if (activityInfo != null) {
- return new AppInfo(mContext, activityInfo, user,
- LauncherAppState.getInstance().getIconCache(),
- UserManagerCompat.getInstance(mContext).isQuietModeEnabled(user),
- false /* useLowResIcon */).makeShortcut();
+ AppInfo appInfo = new AppInfo(mContext, activityInfo, user);
+ final LauncherAppState app = LauncherAppState.getInstance(mContext);
+ // Set default values until proper values is loaded.
+ appInfo.title = "";
+ appInfo.iconBitmap = app.getIconCache().getDefaultIcon(user);
+ final ShortcutInfo si = appInfo.makeShortcut();
+ if (Looper.myLooper() == LauncherModel.getWorkerLooper()) {
+ app.getIconCache().getTitleAndIcon(si, activityInfo, false /* useLowResIcon */);
+ } else {
+ app.getModel().updateAndBindShortcutInfo(new Provider<ShortcutInfo>() {
+ @Override
+ public ShortcutInfo get() {
+ app.getIconCache().getTitleAndIcon(
+ si, activityInfo, false /* useLowResIcon */);
+ return si;
+ }
+ });
+ }
+ return si;
} else if (shortcutInfo != null) {
return new ShortcutInfo(shortcutInfo, mContext);
} else if (providerInfo != null) {
@@ -446,15 +464,14 @@
LauncherAppWidgetInfo widgetInfo = new LauncherAppWidgetInfo(
launchIntent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 0),
info.provider);
- InvariantDeviceProfile idp = LauncherAppState.getInstance()
- .getInvariantDeviceProfile();
+ InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
widgetInfo.minSpanX = info.minSpanX;
widgetInfo.minSpanY = info.minSpanY;
widgetInfo.spanX = Math.min(info.spanX, idp.numColumns);
widgetInfo.spanY = Math.min(info.spanY, idp.numRows);
return widgetInfo;
} else {
- return LauncherAppState.getInstance().getModel().infoFromShortcutIntent(mContext, data);
+ return createShortcutInfo(data, LauncherAppState.getInstance(mContext));
}
}
@@ -472,7 +489,7 @@
try {
Decoder decoder = new Decoder(encoded, context);
if (decoder.optBoolean(APP_SHORTCUT_TYPE_KEY)) {
- LauncherActivityInfoCompat info = LauncherAppsCompat.getInstance(context)
+ LauncherActivityInfo info = LauncherAppsCompat.getInstance(context)
.resolveActivity(decoder.launcherIntent, decoder.user);
return info == null ? null : new PendingInstallShortcutInfo(info, context);
} else if (decoder.optBoolean(DEEPSHORTCUT_TYPE_KEY)) {
@@ -554,7 +571,7 @@
return original;
}
- LauncherActivityInfoCompat info = LauncherAppsCompat.getInstance(original.mContext)
+ LauncherActivityInfo info = LauncherAppsCompat.getInstance(original.mContext)
.resolveActivity(original.launchIntent, original.user);
if (info == null) {
return original;
@@ -598,4 +615,42 @@
return installQueue;
}
}
+
+ private static ShortcutInfo createShortcutInfo(Intent data, LauncherAppState app) {
+ Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
+ String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
+ Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
+
+ if (intent == null) {
+ // If the intent is null, we can't construct a valid ShortcutInfo, so we return null
+ Log.e(TAG, "Can't construct ShorcutInfo with null intent");
+ return null;
+ }
+
+ final ShortcutInfo info = new ShortcutInfo();
+
+ // Only support intents for current user for now. Intents sent from other
+ // users wouldn't get here without intent forwarding anyway.
+ info.user = Process.myUserHandle();
+
+ if (bitmap instanceof Bitmap) {
+ info.iconBitmap = LauncherIcons.createIconBitmap((Bitmap) bitmap, app.getContext());
+ } else {
+ Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
+ if (extra instanceof Intent.ShortcutIconResource) {
+ info.iconResource = (Intent.ShortcutIconResource) extra;
+ info.iconBitmap = LauncherIcons.createIconBitmap(info.iconResource, app.getContext());
+ }
+ }
+ if (info.iconBitmap == null) {
+ info.iconBitmap = app.getIconCache().getDefaultIcon(info.user);
+ }
+
+ info.title = Utilities.trim(name);
+ info.contentDescription = UserManagerCompat.getInstance(app.getContext())
+ .getBadgedLabelForUser(info.title, info.user);
+ info.intent = intent;
+ return info;
+ }
+
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 8e28912..8322f66 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -356,7 +356,7 @@
super.onCreate(savedInstanceState);
- LauncherAppState app = LauncherAppState.getInstance();
+ LauncherAppState app = LauncherAppState.getInstance(this);
// Load configuration-specific DeviceProfile
mDeviceProfile =
@@ -1815,7 +1815,7 @@
// been created. In this case, don't interfere with the new Launcher.
if (mModel.isCurrentCallbacks(this)) {
mModel.stopLoader();
- LauncherAppState.getInstance().setLauncher(null);
+ LauncherAppState.getInstance(this).setLauncher(null);
}
if (mRotationPrefChangeHandler != null) {
@@ -2337,13 +2337,14 @@
showBrokenAppInstallDialog(packageName,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
- startActivitySafely(v, LauncherModel.getMarketIntent(packageName), info);
+ startActivitySafely(
+ v, PackageManagerHelper.getMarketIntent(packageName), info);
}
});
} else {
// Download has started.
final String packageName = info.providerName.getPackageName();
- startActivitySafely(v, LauncherModel.getMarketIntent(packageName), info);
+ startActivitySafely(v, PackageManagerHelper.getMarketIntent(packageName), info);
}
}
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 00e4bf4..4dc5a97 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -48,7 +48,7 @@
private InvariantDeviceProfile mInvariantDeviceProfile;
- public static LauncherAppState getInstance() {
+ public static LauncherAppState getInstance(Context context) {
if (INSTANCE == null) {
INSTANCE = new LauncherAppState();
}
@@ -159,4 +159,11 @@
public InvariantDeviceProfile getInvariantDeviceProfile() {
return mInvariantDeviceProfile;
}
+
+ /**
+ * Shorthand for {@link #getInvariantDeviceProfile()}
+ */
+ public static InvariantDeviceProfile getIDP(Context context) {
+ return LauncherAppState.getInstance(context).getInvariantDeviceProfile();
+ }
}
diff --git a/src/com/android/launcher3/LauncherAppWidgetHostView.java b/src/com/android/launcher3/LauncherAppWidgetHostView.java
index 49bbfd0..1429df5 100644
--- a/src/com/android/launcher3/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/LauncherAppWidgetHostView.java
@@ -33,9 +33,11 @@
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.AdapterView;
import android.widget.Advanceable;
import android.widget.RemoteViews;
+import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragLayer.TouchCompleteListener;
import java.lang.reflect.Method;
@@ -45,7 +47,8 @@
/**
* {@inheritDoc}
*/
-public class LauncherAppWidgetHostView extends AppWidgetHostView implements TouchCompleteListener {
+public class LauncherAppWidgetHostView extends AppWidgetHostView
+ implements TouchCompleteListener, View.OnLongClickListener {
private static final String TAG = "LauncherWidgetHostView";
@@ -56,11 +59,12 @@
// Maintains a list of widget ids which are supposed to be auto advanced.
private static final SparseBooleanArray sAutoAdvanceWidgetIds = new SparseBooleanArray();
- LayoutInflater mInflater;
+ protected final LayoutInflater mInflater;
- private CheckLongPressHelper mLongPressHelper;
- private StylusEventHelper mStylusEventHelper;
- private Context mContext;
+ private final CheckLongPressHelper mLongPressHelper;
+ private final StylusEventHelper mStylusEventHelper;
+ private final Context mContext;
+
@ViewDebug.ExportedProperty(category = "launcher")
private int mPreviousOrientation;
@@ -69,6 +73,7 @@
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mChildrenFocused;
+ private boolean mIsScrollable;
private boolean mIsAttachedToWindow;
private boolean mIsAutoAdvanceRegistered;
private Runnable mAutoAdvanceRunnable;
@@ -86,7 +91,7 @@
public LauncherAppWidgetHostView(Context context) {
super(context);
mContext = context;
- mLongPressHelper = new CheckLongPressHelper(this);
+ mLongPressHelper = new CheckLongPressHelper(this, this);
mStylusEventHelper = new StylusEventHelper(new SimpleOnStylusPressListener(this), this);
mInflater = LayoutInflater.from(context);
setAccessibilityDelegate(Launcher.getLauncher(context).getAccessibilityDelegate());
@@ -104,6 +109,16 @@
}
@Override
+ public boolean onLongClick(View view) {
+ if (mIsScrollable) {
+ DragLayer dragLayer = Launcher.getLauncher(getContext()).getDragLayer();
+ dragLayer.requestDisallowInterceptTouchEvent(false);
+ }
+ view.performLongClick();
+ return true;
+ }
+
+ @Override
protected View getErrorView() {
return mInflater.inflate(R.layout.appwidget_error, this, false);
}
@@ -120,6 +135,24 @@
// The provider info or the views might have changed.
checkIfAutoAdvance();
+
+ mIsScrollable = checkScrollableRecursively(this);
+ }
+
+ private boolean checkScrollableRecursively(ViewGroup viewGroup) {
+ if (viewGroup instanceof AdapterView) {
+ return true;
+ } else {
+ for (int i=0; i < viewGroup.getChildCount(); i++) {
+ View child = viewGroup.getChildAt(i);
+ if (child instanceof ViewGroup) {
+ if (checkScrollableRecursively((ViewGroup) child)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
}
public boolean isReinflateRequired() {
@@ -150,12 +183,18 @@
mLongPressHelper.cancelLongPress();
return true;
}
+
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
+ DragLayer dragLayer = Launcher.getLauncher(getContext()).getDragLayer();
+
+ if (mIsScrollable) {
+ dragLayer.requestDisallowInterceptTouchEvent(true);
+ }
if (!mStylusEventHelper.inStylusButtonPressed()) {
mLongPressHelper.postCheckForLongPress();
}
- Launcher.getLauncher(getContext()).getDragLayer().setTouchCompleteListener(this);
+ dragLayer.setTouchCompleteListener(this);
break;
}
diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
index ab8f395..6cb703b 100644
--- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java
@@ -65,7 +65,7 @@
}
public void initSpans(Context context) {
- InvariantDeviceProfile idp = LauncherAppState.getInstance().getInvariantDeviceProfile();
+ InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
Point paddingLand = idp.landscapeProfile.getTotalWorkspacePadding();
Point paddingPort = idp.portraitProfile.getTotalWorkspacePadding();
@@ -107,8 +107,7 @@
if (isCustomWidget) {
return cache.getFullResIcon(provider.getPackageName(), icon);
}
- return super.loadIcon(context,
- LauncherAppState.getInstance().getInvariantDeviceProfile().fillResIconDpi);
+ return super.loadIcon(context, LauncherAppState.getIDP(context).fillResIconDpi);
}
public String toString(PackageManager pm) {
diff --git a/src/com/android/launcher3/LauncherBackupAgent.java b/src/com/android/launcher3/LauncherBackupAgent.java
index b3e73f7..140794b 100644
--- a/src/com/android/launcher3/LauncherBackupAgent.java
+++ b/src/com/android/launcher3/LauncherBackupAgent.java
@@ -5,11 +5,19 @@
import android.app.backup.BackupDataOutput;
import android.os.ParcelFileDescriptor;
+import com.android.launcher3.logging.FileLog;
import com.android.launcher3.provider.RestoreDbTask;
public class LauncherBackupAgent extends BackupAgent {
@Override
+ public void onCreate() {
+ super.onCreate();
+ // Set the log dir as LauncherAppState is not initialized during restore.
+ FileLog.setDir(getFilesDir());
+ }
+
+ @Override
public void onRestore(
BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) {
// Doesn't do incremental backup/restore
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 58a7495..0907c8c 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -24,44 +24,38 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
-import android.content.Intent.ShortcutIconResource;
import android.content.IntentFilter;
+import android.content.pm.LauncherActivityInfo;
import android.content.pm.PackageManager;
-import android.database.Cursor;
-import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
-import android.os.Parcelable;
import android.os.Process;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
-import android.provider.BaseColumns;
import android.text.TextUtils;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.MutableInt;
import com.android.launcher3.compat.AppWidgetManagerCompat;
-import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.config.ProviderConfig;
import com.android.launcher3.dynamicui.ExtractionUtils;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.AddWorkspaceItemsTask;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.CacheDataUpdatedTask;
import com.android.launcher3.model.ExtendedModelTask;
import com.android.launcher3.model.GridSizeMigrationTask;
+import com.android.launcher3.model.LoaderCursor;
import com.android.launcher3.model.PackageInstallStateChangedTask;
import com.android.launcher3.model.PackageItemInfo;
import com.android.launcher3.model.PackageUpdatedTask;
@@ -77,10 +71,7 @@
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ContentWriter;
-import com.android.launcher3.util.CursorIconInfo;
-import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.LongArrayMap;
import com.android.launcher3.util.ManagedProfileHeuristic;
import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageManagerHelper;
@@ -91,7 +82,6 @@
import java.lang.ref.WeakReference;
import java.net.URISyntaxException;
-import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -346,9 +336,10 @@
final ContentResolver cr = context.getContentResolver();
final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
+ final Context appContext = context.getApplicationContext();
Runnable r = new Runnable() {
public void run() {
- cr.update(uri, writer.getValues(), null, null);
+ cr.update(uri, writer.getValues(appContext), null, null);
updateItemArrays(item, itemId, stackTrace);
}
};
@@ -563,13 +554,14 @@
writer.put(LauncherSettings.Favorites._ID, item.id);
final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
+ final Context appContext = context.getApplicationContext();
Runnable r = new Runnable() {
public void run() {
- cr.insert(LauncherSettings.Favorites.CONTENT_URI, writer.getValues());
+ cr.insert(LauncherSettings.Favorites.CONTENT_URI, writer.getValues(appContext));
synchronized (sBgDataModel) {
checkItemInfoLocked(item.id, item, stackTrace);
- sBgDataModel.addItem(item, true);
+ sBgDataModel.addItem(appContext, item, true);
}
}
};
@@ -598,13 +590,14 @@
public static void deleteItemsFromDatabase(Context context,
final Iterable<? extends ItemInfo> items) {
final ContentResolver cr = context.getContentResolver();
+ final Context appContext = context.getApplicationContext();
Runnable r = new Runnable() {
public void run() {
for (ItemInfo item : items) {
final Uri uri = LauncherSettings.Favorites.getContentUri(item.id);
cr.delete(uri, null, null);
- sBgDataModel.removeItem(item);
+ sBgDataModel.removeItem(appContext, item);
}
}
};
@@ -664,16 +657,17 @@
*/
public static void deleteFolderAndContentsFromDatabase(Context context, final FolderInfo info) {
final ContentResolver cr = context.getContentResolver();
+ final Context appContext = context.getApplicationContext();
Runnable r = new Runnable() {
public void run() {
cr.delete(LauncherSettings.Favorites.CONTENT_URI,
LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
- sBgDataModel.removeItem(info.contents);
+ sBgDataModel.removeItem(appContext, info.contents);
info.contents.clear();
cr.delete(LauncherSettings.Favorites.getContentUri(info.id), null, null);
- sBgDataModel.removeItem(info);
+ sBgDataModel.removeItem(appContext, info);
}
};
runOnWorkerThread(r);
@@ -1096,96 +1090,6 @@
}
}
- // check & update map of what's occupied; used to discard overlapping/invalid items
- private boolean checkItemPlacement(LongArrayMap<GridOccupancy> occupied, ItemInfo item,
- ArrayList<Long> workspaceScreens) {
- LauncherAppState app = LauncherAppState.getInstance();
- InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
-
- long containerIndex = item.screenId;
- if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- // Return early if we detect that an item is under the hotseat button
- if (!FeatureFlags.NO_ALL_APPS_ICON &&
- profile.isAllAppsButtonRank((int) item.screenId)) {
- Log.e(TAG, "Error loading shortcut into hotseat " + item
- + " into position (" + item.screenId + ":" + item.cellX + ","
- + item.cellY + ") occupied by all apps");
- return false;
- }
-
- final GridOccupancy hotseatOccupancy =
- occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);
-
- if (item.screenId >= profile.numHotseatIcons) {
- Log.e(TAG, "Error loading shortcut " + item
- + " into hotseat position " + item.screenId
- + ", position out of bounds: (0 to " + (profile.numHotseatIcons - 1)
- + ")");
- return false;
- }
-
- if (hotseatOccupancy != null) {
- if (hotseatOccupancy.cells[(int) item.screenId][0]) {
- Log.e(TAG, "Error loading shortcut into hotseat " + item
- + " into position (" + item.screenId + ":" + item.cellX + ","
- + item.cellY + ") already occupied");
- return false;
- } else {
- hotseatOccupancy.cells[(int) item.screenId][0] = true;
- return true;
- }
- } else {
- final GridOccupancy occupancy = new GridOccupancy(profile.numHotseatIcons, 1);
- occupancy.cells[(int) item.screenId][0] = true;
- occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, occupancy);
- return true;
- }
- } else if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
- if (!workspaceScreens.contains((Long) item.screenId)) {
- // The item has an invalid screen id.
- return false;
- }
- } else {
- // Skip further checking if it is not the hotseat or workspace container
- return true;
- }
-
- final int countX = profile.numColumns;
- final int countY = profile.numRows;
- if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
- item.cellX < 0 || item.cellY < 0 ||
- item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {
- Log.e(TAG, "Error loading shortcut " + item
- + " into cell (" + containerIndex + "-" + item.screenId + ":"
- + item.cellX + "," + item.cellY
- + ") out of screen bounds ( " + countX + "x" + countY + ")");
- return false;
- }
-
- if (!occupied.containsKey(item.screenId)) {
- GridOccupancy screen = new GridOccupancy(countX + 1, countY + 1);
- if (item.screenId == Workspace.FIRST_SCREEN_ID) {
- // Mark the first row as occupied (if the feature is enabled)
- // in order to account for the QSB.
- screen.markCells(0, 0, countX + 1, 1, FeatureFlags.QSB_ON_FIRST_SCREEN);
- }
- occupied.put(item.screenId, screen);
- }
- final GridOccupancy occupancy = occupied.get(item.screenId);
-
- // Check if any workspace icons overlap with each other
- if (occupancy.isRegionVacant(item.cellX, item.cellY, item.spanX, item.spanY)) {
- occupancy.markCells(item, true);
- return true;
- } else {
- Log.e(TAG, "Error loading shortcut " + item
- + " into cell (" + containerIndex + "-" + item.screenId + ":"
- + item.cellX + "," + item.cellX + "," + item.spanX + "," + item.spanY
- + ") already occupied");
- return false;
- }
- }
-
private void loadWorkspace() {
if (LauncherAppState.PROFILE_STARTUP) {
Trace.beginSection("Loading Workspace");
@@ -1201,8 +1105,7 @@
final boolean isSdCardReady = Utilities.isBootCompleted();
final MultiHashMap<UserHandle, String> pendingPackages = new MultiHashMap<>();
- LauncherAppState app = LauncherAppState.getInstance();
- InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
+ InvariantDeviceProfile profile = mApp.getInvariantDeviceProfile();
int countX = profile.numColumns;
int countY = profile.numRows;
@@ -1237,37 +1140,19 @@
.getInstance(mContext).updateAndGetActiveSessionCache();
sBgDataModel.workspaceScreens.addAll(loadWorkspaceScreensDb(mContext));
- final ArrayList<Long> itemsToRemove = new ArrayList<>();
- final ArrayList<Long> restoredRows = new ArrayList<>();
Map<ShortcutKey, ShortcutInfoCompat> shortcutKeyToPinnedShortcuts = new HashMap<>();
- final Uri contentUri = LauncherSettings.Favorites.CONTENT_URI;
- if (DEBUG_LOADERS) Log.d(TAG, "loading model from " + contentUri);
- final Cursor c = contentResolver.query(contentUri, null, null, null, null);
+ final LoaderCursor c = new LoaderCursor(contentResolver.query(
+ LauncherSettings.Favorites.CONTENT_URI, null, null, null, null), mApp);
- // +1 for the hotseat (it can be larger than the workspace)
- // Load workspace in reverse order to ensure that latest items are loaded first (and
- // before any earlier duplicates)
- final LongArrayMap<GridOccupancy> occupied = new LongArrayMap<>();
HashMap<ComponentKey, AppWidgetProviderInfo> widgetProvidersMap = null;
try {
- final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
final int intentIndex = c.getColumnIndexOrThrow
(LauncherSettings.Favorites.INTENT);
- final int containerIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.CONTAINER);
- final int itemTypeIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.ITEM_TYPE);
final int appWidgetIdIndex = c.getColumnIndexOrThrow(
LauncherSettings.Favorites.APPWIDGET_ID);
final int appWidgetProviderIndex = c.getColumnIndexOrThrow(
LauncherSettings.Favorites.APPWIDGET_PROVIDER);
- final int screenIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.SCREEN);
- final int cellXIndex = c.getColumnIndexOrThrow
- (LauncherSettings.Favorites.CELLX);
- final int cellYIndex = c.getColumnIndexOrThrow
- (LauncherSettings.Favorites.CELLY);
final int spanXIndex = c.getColumnIndexOrThrow
(LauncherSettings.Favorites.SPANX);
final int spanYIndex = c.getColumnIndexOrThrow(
@@ -1276,13 +1161,10 @@
LauncherSettings.Favorites.RANK);
final int restoredIndex = c.getColumnIndexOrThrow(
LauncherSettings.Favorites.RESTORED);
- final int profileIdIndex = c.getColumnIndexOrThrow(
- LauncherSettings.Favorites.PROFILE_ID);
final int optionsIndex = c.getColumnIndexOrThrow(
LauncherSettings.Favorites.OPTIONS);
- final CursorIconInfo cursorIconInfo = new CursorIconInfo(mContext, c);
- final LongSparseArray<UserHandle> allUsers = new LongSparseArray<>();
+ final LongSparseArray<UserHandle> allUsers = c.allUsers;
final LongSparseArray<Boolean> quietMode = new LongSparseArray<>();
final LongSparseArray<Boolean> unlockedUsers = new LongSparseArray<>();
for (UserHandle user : mUserManager.getUserProfiles()) {
@@ -1314,45 +1196,42 @@
ShortcutInfo info;
String intentDescription;
LauncherAppWidgetInfo appWidgetInfo;
- int container;
- long id;
- long serialNumber;
Intent intent;
- UserHandle user;
String targetPackage;
while (!mStopped && c.moveToNext()) {
try {
- int itemType = c.getInt(itemTypeIndex);
+ if (c.user == null) {
+ // User has been deleted, remove the item.
+ c.markDeleted("User has been deleted");
+ continue;
+ }
+
boolean restored = 0 != c.getInt(restoredIndex);
boolean allowMissingTarget = false;
- container = c.getInt(containerIndex);
-
- switch (itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
- case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
- id = c.getLong(idIndex);
- intentDescription = c.getString(intentIndex);
- serialNumber = c.getInt(profileIdIndex);
- user = allUsers.get(serialNumber);
- int promiseType = c.getInt(restoredIndex);
- int disabledState = 0;
- boolean itemReplaced = false;
- targetPackage = null;
- if (user == null) {
- // User has been deleted remove the item.
- itemsToRemove.add(id);
+ switch (c.itemType) {
+ case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: {
+ if (!Process.myUserHandle().equals(c.user)) {
+ c.markDeleted("Legacy shortcuts are only allowed for default user");
continue;
}
+ // Follow through.
+ }
+ case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+ case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
+ intentDescription = c.getString(intentIndex);
+ int promiseType = c.getInt(restoredIndex);
+ int disabledState = 0;
+ targetPackage = null;
+
try {
intent = Intent.parseUri(intentDescription, 0);
ComponentName cn = intent.getComponent();
if (cn != null && cn.getPackageName() != null) {
boolean validPkg = launcherApps.isPackageEnabledForProfile(
- cn.getPackageName(), user);
+ cn.getPackageName(), c.user);
boolean validComponent = validPkg &&
- launcherApps.isActivityEnabledForProfile(cn, user);
+ launcherApps.isActivityEnabledForProfile(cn, c.user);
if (validPkg) {
targetPackage = cn.getPackageName();
}
@@ -1360,10 +1239,10 @@
if (validComponent) {
if (restored) {
// no special handling necessary for this item
- restoredRows.add(id);
+ c.markRestored();
restored = false;
}
- if (quietMode.get(serialNumber)) {
+ if (quietMode.get(c.serialNumber)) {
disabledState = ShortcutInfo.FLAG_DISABLED_QUIET_USER;
}
} else if (validPkg) {
@@ -1374,22 +1253,20 @@
intent = manager.getLaunchIntentForPackage(
cn.getPackageName());
if (intent != null) {
- ContentValues values = new ContentValues();
- values.put(LauncherSettings.Favorites.INTENT,
- intent.toUri(0));
- updateItem(id, values);
+ c.updater().put(
+ LauncherSettings.Favorites.INTENT,
+ intent.toUri(0)).commit();
}
}
if (intent == null) {
// The app is installed but the component is no
// longer available.
- FileLog.d(TAG, "Invalid component removed: " + cn);
- itemsToRemove.add(id);
+ c.markDeleted("Invalid component removed: " + cn);
continue;
} else {
// no special handling necessary for this item
- restoredRows.add(id);
+ c.markRestored();
restored = false;
}
} else if (restored) {
@@ -1402,32 +1279,11 @@
} else if (installingPkgs.containsKey(cn.getPackageName())) {
// App restore has started. Update the flag
promiseType |= ShortcutInfo.FLAG_RESTORE_STARTED;
- ContentValues values = new ContentValues();
- values.put(LauncherSettings.Favorites.RESTORED,
- promiseType);
- updateItem(id, values);
- } else if ((promiseType & ShortcutInfo.FLAG_RESTORED_APP_TYPE) != 0) {
- // This is a common app. Try to replace this.
- int appType = CommonAppTypeParser.decodeItemTypeFromFlag(promiseType);
- CommonAppTypeParser parser = new CommonAppTypeParser(id, appType, context);
- if (parser.findDefaultApp()) {
- // Default app found. Replace it.
- intent = parser.parsedIntent;
- cn = intent.getComponent();
- ContentValues values = parser.parsedValues;
- values.put(LauncherSettings.Favorites.RESTORED, 0);
- updateItem(id, values);
- restored = false;
- itemReplaced = true;
-
- } else {
- FileLog.d(TAG, "Unrestored package removed: " + cn);
- itemsToRemove.add(id);
- continue;
- }
+ c.updater().put(
+ LauncherSettings.Favorites.RESTORED,
+ promiseType).commit();
} else {
- FileLog.d(TAG, "Unrestored package removed: " + cn);
- itemsToRemove.add(id);
+ c.markDeleted("Unrestored package removed: " + cn);
continue;
}
} else if (PackageManagerHelper.isAppOnSdcard(
@@ -1439,79 +1295,64 @@
// SdCard is not ready yet. Package might get available,
// once it is ready.
Log.d(TAG, "Invalid package: " + cn + " (check again later)");
- pendingPackages.addToList(user, cn.getPackageName());
+ pendingPackages.addToList(c.user, cn.getPackageName());
allowMissingTarget = true;
// Add the icon on the workspace anyway.
} else {
// Do not wait for external media load anymore.
// Log the invalid package, and remove it
- FileLog.d(TAG, "Invalid package removed: " + cn);
- itemsToRemove.add(id);
+ c.markDeleted("Invalid package removed: " + cn);
continue;
}
} else if (cn == null) {
// For shortcuts with no component, keep them as they are
- restoredRows.add(id);
+ c.markRestored();
restored = false;
}
} catch (URISyntaxException e) {
- FileLog.d(TAG, "Invalid uri: " + intentDescription);
- itemsToRemove.add(id);
+ c.markDeleted("Invalid uri: " + intentDescription);
continue;
}
- boolean useLowResIcon = container >= 0 &&
+ boolean useLowResIcon = !c.isOnWorkspaceOrHotseat() &&
c.getInt(rankIndex) >= FolderIcon.NUM_ITEMS_IN_PREVIEW;
- if (itemReplaced) {
- if (user.equals(Process.myUserHandle())) {
- info = getAppShortcutInfo(intent, user, null,
- cursorIconInfo, false, useLowResIcon);
- } else {
- // Don't replace items for other profiles.
- itemsToRemove.add(id);
- continue;
- }
- } else if (restored) {
- if (user.equals(Process.myUserHandle())) {
- info = getRestoredItemInfo(c, intent,
- promiseType, itemType, cursorIconInfo);
- intent = getRestoredItemIntent(c, context, intent);
+ if (restored) {
+ if (c.user.equals(Process.myUserHandle())) {
+ info = c.getRestoredItemInfo(intent, promiseType);
+ intent = PackageManagerHelper.getMarketIntent(
+ intent.getComponent().getPackageName());
} else {
// Don't restore items for other profiles.
- itemsToRemove.add(id);
+ c.markDeleted("Restore from managed profile not supported");
continue;
}
- } else if (itemType ==
+ } else if (c.itemType ==
LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
- info = getAppShortcutInfo(intent, user, c,
- cursorIconInfo, allowMissingTarget, useLowResIcon);
- } else if (itemType ==
+ info = c.getAppShortcutInfo(
+ intent, allowMissingTarget, useLowResIcon);
+ } else if (c.itemType ==
LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
- ShortcutKey key = ShortcutKey.fromIntent(intent, user);
- if (unlockedUsers.get(serialNumber)) {
+ ShortcutKey key = ShortcutKey.fromIntent(intent, c.user);
+ if (unlockedUsers.get(c.serialNumber)) {
ShortcutInfoCompat pinnedShortcut =
shortcutKeyToPinnedShortcuts.get(key);
if (pinnedShortcut == null) {
// The shortcut is no longer valid.
- itemsToRemove.add(id);
+ c.markDeleted("Pinned shortcut not found");
continue;
}
info = new ShortcutInfo(pinnedShortcut, context);
intent = info.intent;
} else {
// Create a shortcut info in disabled mode for now.
- info = new ShortcutInfo();
- info.user = user;
- info.itemType = itemType;
- loadInfoFromCursor(info, c, cursorIconInfo);
-
+ info = c.loadSimpleShortcut();
info.isDisabled |= ShortcutInfo.FLAG_DISABLED_LOCKED_USER;
}
} else { // item type == ITEM_TYPE_SHORTCUT
- info = getShortcutInfo(c, cursorIconInfo);
+ info = c.loadSimpleShortcut();
// Shortcuts are only available on the primary profile
if (PackageManagerHelper.isAppSuspended(manager, targetPackage)) {
@@ -1532,30 +1373,23 @@
}
if (info != null) {
- info.id = id;
+ c.applyCommonProperties(info);
+
info.intent = intent;
- info.container = container;
- info.screenId = c.getInt(screenIndex);
- info.cellX = c.getInt(cellXIndex);
- info.cellY = c.getInt(cellYIndex);
info.rank = c.getInt(rankIndex);
info.spanX = 1;
info.spanY = 1;
- info.intent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);
+ // TODO: Remove this extra. Instead we should be using
+ // itemInfo#user.
+ info.intent.putExtra(ItemInfo.EXTRA_PROFILE, c.serialNumber);
if (info.promisedIntent != null) {
- info.promisedIntent.putExtra(ItemInfo.EXTRA_PROFILE, serialNumber);
+ info.promisedIntent.putExtra(ItemInfo.EXTRA_PROFILE, c.serialNumber);
}
info.isDisabled |= disabledState;
if (isSafeMode && !Utilities.isSystemApp(context, intent)) {
info.isDisabled |= ShortcutInfo.FLAG_DISABLED_SAFEMODE;
}
- // check & update map of what's occupied
- if (!checkItemPlacement(occupied, info, sBgDataModel.workspaceScreens)) {
- itemsToRemove.add(id);
- break;
- }
-
if (restored) {
ComponentName cn = info.getTargetComponent();
if (cn != null) {
@@ -1568,55 +1402,38 @@
}
}
- sBgDataModel.addItem(info, false);
+ c.checkAndAddItem(info, sBgDataModel);
} else {
throw new RuntimeException("Unexpected null ShortcutInfo");
}
break;
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- id = c.getLong(idIndex);
- FolderInfo folderInfo = sBgDataModel.findOrMakeFolder(id);
+ FolderInfo folderInfo = sBgDataModel.findOrMakeFolder(c.id);
+ c.applyCommonProperties(folderInfo);
// Do not trim the folder label, as is was set by the user.
- folderInfo.title = c.getString(cursorIconInfo.titleIndex);
- folderInfo.id = id;
- folderInfo.container = container;
- folderInfo.screenId = c.getInt(screenIndex);
- folderInfo.cellX = c.getInt(cellXIndex);
- folderInfo.cellY = c.getInt(cellYIndex);
+ folderInfo.title = c.getString(c.titleIndex);
folderInfo.spanX = 1;
folderInfo.spanY = 1;
folderInfo.options = c.getInt(optionsIndex);
- // check & update map of what's occupied
- if (!checkItemPlacement(occupied, folderInfo, sBgDataModel.workspaceScreens)) {
- itemsToRemove.add(id);
- break;
- }
if (restored) {
// no special handling required for restored folders
- restoredRows.add(id);
+ c.markRestored();
}
- sBgDataModel.addItem(folderInfo, false);
+ c.checkAndAddItem(folderInfo, sBgDataModel);
break;
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
case LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET:
// Read all Launcher-specific widget details
- boolean customWidget = itemType ==
+ boolean customWidget = c.itemType ==
LauncherSettings.Favorites.ITEM_TYPE_CUSTOM_APPWIDGET;
int appWidgetId = c.getInt(appWidgetIdIndex);
- serialNumber = c.getLong(profileIdIndex);
String savedProvider = c.getString(appWidgetProviderIndex);
- id = c.getLong(idIndex);
- user = allUsers.get(serialNumber);
- if (user == null) {
- itemsToRemove.add(id);
- continue;
- }
final ComponentName component =
ComponentName.unflattenFromString(savedProvider);
@@ -1634,14 +1451,14 @@
final AppWidgetProviderInfo provider = widgetProvidersMap.get(
new ComponentKey(
ComponentName.unflattenFromString(savedProvider),
- user));
+ c.user));
final boolean isProviderReady = isValidProvider(provider);
if (!isSafeMode && !customWidget &&
wasProviderReady && !isProviderReady) {
- FileLog.d(TAG, "Deleting widget that isn't installed anymore: "
+ c.markDeleted(
+ "Deleting widget that isn't installed anymore: "
+ provider);
- itemsToRemove.add(id);
} else {
if (isProviderReady) {
appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
@@ -1666,7 +1483,7 @@
}
appWidgetInfo.restoreStatus = status;
} else {
- Log.v(TAG, "Widget restore pending id=" + id
+ Log.v(TAG, "Widget restore pending id=" + c.id
+ " appWidgetId=" + appWidgetId
+ " status =" + restoreStatus);
appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
@@ -1681,8 +1498,7 @@
appWidgetInfo.restoreStatus |=
LauncherAppWidgetInfo.FLAG_RESTORE_STARTED;
} else if (!isSafeMode) {
- FileLog.d(TAG, "Unrestored widget removed: " + component);
- itemsToRemove.add(id);
+ c.markDeleted("Unrestored widget removed: " + component);
continue;
}
@@ -1698,44 +1514,31 @@
}
}
- appWidgetInfo.id = id;
- appWidgetInfo.screenId = c.getInt(screenIndex);
- appWidgetInfo.cellX = c.getInt(cellXIndex);
- appWidgetInfo.cellY = c.getInt(cellYIndex);
+ c.applyCommonProperties(appWidgetInfo);
appWidgetInfo.spanX = c.getInt(spanXIndex);
appWidgetInfo.spanY = c.getInt(spanYIndex);
- appWidgetInfo.user = user;
+ appWidgetInfo.user = c.user;
- if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP &&
- container != LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
- Log.e(TAG, "Widget found where container != " +
+ if (!c.isOnWorkspaceOrHotseat()) {
+ c.markDeleted("Widget found where container != " +
"CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");
- itemsToRemove.add(id);
continue;
}
- appWidgetInfo.container = container;
- // check & update map of what's occupied
- if (!checkItemPlacement(occupied, appWidgetInfo, sBgDataModel.workspaceScreens)) {
- itemsToRemove.add(id);
- break;
- }
-
if (!customWidget) {
String providerName =
appWidgetInfo.providerName.flattenToString();
if (!providerName.equals(savedProvider) ||
(appWidgetInfo.restoreStatus != restoreStatus)) {
- ContentValues values = new ContentValues();
- values.put(
- LauncherSettings.Favorites.APPWIDGET_PROVIDER,
- providerName);
- values.put(LauncherSettings.Favorites.RESTORED,
- appWidgetInfo.restoreStatus);
- updateItem(id, values);
+ c.updater()
+ .put(LauncherSettings.Favorites.APPWIDGET_PROVIDER,
+ providerName)
+ .put(LauncherSettings.Favorites.RESTORED,
+ appWidgetInfo.restoreStatus)
+ .commit();
}
}
- sBgDataModel.addItem(appWidgetInfo, false);
+ c.checkAndAddItem(appWidgetInfo, sBgDataModel);
}
break;
}
@@ -1753,16 +1556,8 @@
return;
}
- if (itemsToRemove.size() > 0) {
- // Remove dead items
- contentResolver.delete(LauncherSettings.Favorites.CONTENT_URI,
- Utilities.createDbSelectionQuery(
- LauncherSettings.Favorites._ID, itemsToRemove), null);
- if (DEBUG_LOADERS) {
- Log.d(TAG, "Removed = " + Utilities.createDbSelectionQuery(
- LauncherSettings.Favorites._ID, itemsToRemove));
- }
-
+ // Remove dead items
+ if (c.commitDeleted()) {
// Remove any empty folder
ArrayList<Long> deletedFolderIds = (ArrayList<Long>) LauncherSettings.Settings
.call(contentResolver,
@@ -1803,15 +1598,7 @@
}
}
- if (restoredRows.size() > 0) {
- // Update restored items that no longer require special handling
- ContentValues values = new ContentValues();
- values.put(LauncherSettings.Favorites.RESTORED, 0);
- contentResolver.update(LauncherSettings.Favorites.CONTENT_URI, values,
- Utilities.createDbSelectionQuery(
- LauncherSettings.Favorites._ID, restoredRows), null);
- }
-
+ c.commitRestoredItems();
if (!isSdCardReady && !pendingPackages.isEmpty()) {
context.registerReceiver(
new SdCardAvailableReceiver(
@@ -1822,7 +1609,7 @@
}
// Remove any empty screens
- ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgDataModel.workspaceScreens);
+ ArrayList<Long> unusedScreens = new ArrayList<>(sBgDataModel.workspaceScreens);
for (ItemInfo item: sBgDataModel.itemsIdMap) {
long screenId = item.screenId;
if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
@@ -1836,40 +1623,12 @@
sBgDataModel.workspaceScreens.removeAll(unusedScreens);
updateWorkspaceScreenOrder(context, sBgDataModel.workspaceScreens);
}
-
- if (DEBUG_LOADERS) {
- Log.d(TAG, "loaded workspace in " + (SystemClock.uptimeMillis()-t) + "ms");
- Log.d(TAG, "workspace layout: ");
- int nScreens = occupied.size();
- for (int y = 0; y < countY; y++) {
- String line = "";
-
- for (int i = 0; i < nScreens; i++) {
- long screenId = occupied.keyAt(i);
- if (screenId > 0) {
- line += " | ";
- }
- }
- Log.d(TAG, "[ " + line + " ]");
- }
- }
}
if (LauncherAppState.PROFILE_STARTUP) {
Trace.endSection();
}
}
- /**
- * Partially updates the item without any notification. Must be called on the worker thread.
- */
- private void updateItem(long itemId, ContentValues update) {
- mContext.getContentResolver().update(
- LauncherSettings.Favorites.CONTENT_URI,
- update,
- BaseColumns._ID + "= ?",
- new String[]{Long.toString(itemId)});
- }
-
/** Filters the set of items who are directly or indirectly (via another container) on the
* specified screen. */
private void filterCurrentWorkspaceItems(long currentScreenId,
@@ -1937,8 +1696,7 @@
/** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to
* right) */
private void sortWorkspaceItemsSpatially(ArrayList<ItemInfo> workspaceItems) {
- final LauncherAppState app = LauncherAppState.getInstance();
- final InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
+ final InvariantDeviceProfile profile = mApp.getInvariantDeviceProfile();
final int screenCols = profile.numColumns;
final int screenCellCount = profile.numColumns * profile.numRows;
Collections.sort(workspaceItems, new Comparator<ItemInfo>() {
@@ -2257,7 +2015,7 @@
for (UserHandle user : profiles) {
// Query for the set of apps
final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
- final List<LauncherActivityInfoCompat> apps = mLauncherApps.getActivityList(null, user);
+ final List<LauncherActivityInfo> apps = mLauncherApps.getActivityList(null, user);
if (DEBUG_LOADERS) {
Log.d(TAG, "getActivityList took "
+ (SystemClock.uptimeMillis()-qiaTime) + "ms for user " + user);
@@ -2271,9 +2029,9 @@
boolean quietMode = mUserManager.isQuietModeEnabled(user);
// Create the ApplicationInfos
for (int i = 0; i < apps.size(); i++) {
- LauncherActivityInfoCompat app = apps.get(i);
+ LauncherActivityInfo app = apps.get(i);
// This builds the icon bitmaps.
- mBgAllAppsList.add(new AppInfo(mContext, app, user, mIconCache, quietMode));
+ mBgAllAppsList.add(new AppInfo(mContext, app, user, quietMode), app);
}
final ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(mContext, user);
@@ -2465,17 +2223,16 @@
}
/**
- * Repopulates the shortcut info, possibly updating any icon already on the workspace.
+ * Utility method to update a shortcut on the background thread.
*/
- public void updateShortcutInfo(final ShortcutInfoCompat fullDetail, final ShortcutInfo info) {
+ public void updateAndBindShortcutInfo(final Provider<ShortcutInfo> shortcutProvider) {
enqueueModelUpdateTask(new ExtendedModelTask() {
@Override
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
- info.updateFromDeepShortcutInfo(fullDetail, app.getContext());
-
+ ShortcutInfo info = shortcutProvider.get();
ArrayList<ShortcutInfo> update = new ArrayList<>();
update.add(info);
- bindUpdatedShortcuts(update, fullDetail.getUserHandle());
+ bindUpdatedShortcuts(update, info.user);
}
});
}
@@ -2506,184 +2263,11 @@
bindWidgetsModel(callbacks);
// update the Widget entries inside DB on the worker thread.
- LauncherAppState.getInstance().getWidgetCache().removeObsoletePreviews(allWidgets);
+ mApp.getWidgetCache().removeObsoletePreviews(allWidgets);
}
});
}
- /**
- * Make an ShortcutInfo object for a restored application or shortcut item that points
- * to a package that is not yet installed on the system.
- */
- public ShortcutInfo getRestoredItemInfo(Cursor c, Intent intent,
- int promiseType, int itemType, CursorIconInfo iconInfo) {
- final ShortcutInfo info = new ShortcutInfo();
- info.user = Process.myUserHandle();
- info.promisedIntent = intent;
-
- info.iconBitmap = iconInfo.loadIcon(c, info);
- // the fallback icon
- if (info.iconBitmap == null) {
- mIconCache.getTitleAndIcon(info, false /* useLowResIcon */);
- }
-
- if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {
- String title = iconInfo.getTitle(c);
- if (!TextUtils.isEmpty(title)) {
- info.title = Utilities.trim(title);
- }
- } else if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {
- if (TextUtils.isEmpty(info.title)) {
- info.title = iconInfo.getTitle(c);
- }
- } else {
- throw new InvalidParameterException("Invalid restoreType " + promiseType);
- }
-
- info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);
- info.itemType = itemType;
- info.status = promiseType;
- return info;
- }
-
- /**
- * Make an Intent object for a restored application or shortcut item that points
- * to the market page for the item.
- */
- @Thunk Intent getRestoredItemIntent(Cursor c, Context context, Intent intent) {
- ComponentName componentName = intent.getComponent();
- return getMarketIntent(componentName.getPackageName());
- }
-
- static Intent getMarketIntent(String packageName) {
- return new Intent(Intent.ACTION_VIEW)
- .setData(new Uri.Builder()
- .scheme("market")
- .authority("details")
- .appendQueryParameter("id", packageName)
- .build());
- }
-
- /**
- * Make an ShortcutInfo object for a shortcut that is an application.
- *
- * If c is not null, then it will be used to fill in missing data like the title and icon.
- */
- public ShortcutInfo getAppShortcutInfo(Intent intent, UserHandle user, Cursor c,
- CursorIconInfo iconInfo, boolean allowMissingTarget, boolean useLowResIcon) {
- if (user == null) {
- Log.d(TAG, "Null user found in getShortcutInfo");
- return null;
- }
-
- ComponentName componentName = intent.getComponent();
- if (componentName == null) {
- Log.d(TAG, "Missing component found in getShortcutInfo");
- return null;
- }
-
- Intent newIntent = new Intent(intent.getAction(), null);
- newIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- newIntent.setComponent(componentName);
- LauncherActivityInfoCompat lai = mLauncherApps.resolveActivity(newIntent, user);
- if ((lai == null) && !allowMissingTarget) {
- Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName);
- return null;
- }
-
- final ShortcutInfo info = new ShortcutInfo();
- info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
- info.user = user;
- info.intent = newIntent;
-
- mIconCache.getTitleAndIcon(info, lai, useLowResIcon);
- if (mIconCache.isDefaultIcon(info.iconBitmap, user) && c != null) {
- Bitmap icon = iconInfo.loadIcon(c);
- info.iconBitmap = icon != null ? icon : mIconCache.getDefaultIcon(user);
- }
-
- if (lai != null && PackageManagerHelper.isAppSuspended(lai.getApplicationInfo())) {
- info.isDisabled = ShortcutInfo.FLAG_DISABLED_SUSPENDED;
- }
-
- // from the db
- if (TextUtils.isEmpty(info.title) && c != null) {
- info.title = iconInfo.getTitle(c);
- }
-
- // fall back to the class name of the activity
- if (info.title == null) {
- info.title = componentName.getClassName();
- }
-
- info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);
- return info;
- }
-
- /**
- * Make an ShortcutInfo object for a shortcut that isn't an application.
- */
- @Thunk ShortcutInfo getShortcutInfo(Cursor c, CursorIconInfo iconInfo) {
- final ShortcutInfo info = new ShortcutInfo();
- // Non-app shortcuts are only supported for current user.
- info.user = Process.myUserHandle();
- info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
-
- // TODO: If there's an explicit component and we can't install that, delete it.
-
- loadInfoFromCursor(info, c, iconInfo);
- return info;
- }
-
- /**
- * Make an ShortcutInfo object for a shortcut that isn't an application.
- */
- public void loadInfoFromCursor(ShortcutInfo info, Cursor c, CursorIconInfo iconInfo) {
- info.title = iconInfo.getTitle(c);
- info.iconBitmap = iconInfo.loadIcon(c, info);
- // the fallback icon
- if (info.iconBitmap == null) {
- info.iconBitmap = mIconCache.getDefaultIcon(info.user);
- }
- }
-
- ShortcutInfo infoFromShortcutIntent(Context context, Intent data) {
- Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
- String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
- Parcelable bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
-
- if (intent == null) {
- // If the intent is null, we can't construct a valid ShortcutInfo, so we return null
- Log.e(TAG, "Can't construct ShorcutInfo with null intent");
- return null;
- }
-
- final ShortcutInfo info = new ShortcutInfo();
-
- // Only support intents for current user for now. Intents sent from other
- // users wouldn't get here without intent forwarding anyway.
- info.user = Process.myUserHandle();
-
- if (bitmap instanceof Bitmap) {
- info.iconBitmap = LauncherIcons.createIconBitmap((Bitmap) bitmap, context);
- } else {
- Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
- if (extra instanceof ShortcutIconResource) {
- info.iconResource = (ShortcutIconResource) extra;
- info.iconBitmap = LauncherIcons.createIconBitmap(info.iconResource, context);
- }
- }
- if (info.iconBitmap == null) {
- info.iconBitmap = mIconCache.getDefaultIcon(info.user);
- }
-
- info.title = Utilities.trim(name);
- info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);
- info.intent = intent;
-
- return info;
- }
-
static boolean isValidProvider(AppWidgetProviderInfo provider) {
return (provider != null) && (provider.provider != null)
&& (provider.provider.getPackageName() != null);
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 8f56eb6..6266fae 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -556,8 +556,7 @@
}
private DefaultLayoutParser getDefaultLayoutParser(AppWidgetHost widgetHost) {
- int defaultLayout = LauncherAppState.getInstance()
- .getInvariantDeviceProfile().defaultLayoutId;
+ int defaultLayout = LauncherAppState.getIDP(getContext()).defaultLayoutId;
return new DefaultLayoutParser(getContext(), widgetHost,
mOpenHelper, getContext().getResources(), defaultLayout);
}
diff --git a/src/com/android/launcher3/PendingAppWidgetHostView.java b/src/com/android/launcher3/PendingAppWidgetHostView.java
index 2976807..3256df6 100644
--- a/src/com/android/launcher3/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/PendingAppWidgetHostView.java
@@ -17,7 +17,6 @@
package com.android.launcher3;
import android.content.Context;
-import android.content.Intent;
import android.content.res.Resources.Theme;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -35,8 +34,11 @@
import android.view.View.OnClickListener;
import com.android.launcher3.graphics.DrawableFactory;
+import com.android.launcher3.IconCache.ItemInfoUpdateReceiver;
+import com.android.launcher3.model.PackageItemInfo;
-public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implements OnClickListener {
+public class PendingAppWidgetHostView extends LauncherAppWidgetHostView
+ implements OnClickListener, ItemInfoUpdateReceiver {
private static final float SETUP_ICON_SIZE_FACTOR = 2f / 5;
private static final float MIN_SATUNATION = 0.7f;
@@ -47,7 +49,6 @@
private OnClickListener mClickListener;
private final LauncherAppWidgetInfo mInfo;
private final int mStartState;
- private final Intent mIconLookupIntent;
private final boolean mDisabledForSafeMode;
private Launcher mLauncher;
@@ -68,7 +69,6 @@
mLauncher = Launcher.getLauncher(context);
mInfo = info;
mStartState = info.restoreStatus;
- mIconLookupIntent = new Intent().setComponent(info.providerName);
mDisabledForSafeMode = disabledForSafeMode;
mPaint = new TextPaint();
@@ -79,9 +79,13 @@
setWillNotDraw(false);
setElevation(getResources().getDimension(R.dimen.pending_widget_elevation));
- updateIcon(cache);
updateAppWidget(null);
setOnClickListener(mLauncher);
+
+ // Load icon
+ PackageItemInfo item = new PackageItemInfo(info.providerName.getPackageName());
+ item.user = info.user;
+ cache.updateIconInBackground(this, item);
}
@Override
@@ -117,8 +121,9 @@
mDrawableSizeChanged = true;
}
- private void updateIcon(IconCache cache) {
- Bitmap icon = cache.getIcon(mIconLookupIntent, mInfo.user);
+ @Override
+ public void reapplyItemInfo(ItemInfoWithIcon info) {
+ Bitmap icon = info.iconBitmap;
if (mIcon == icon) {
return;
}
@@ -157,6 +162,7 @@
}
mDrawableSizeChanged = true;
}
+ invalidate();
}
private void updateSettingColor() {
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index 05fb1ed..8c83dff 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -68,6 +68,7 @@
* Indicates if it represents a common type mentioned in {@link CommonAppTypeParser}.
* Upto 15 different types supported.
*/
+ @Deprecated
public static final int FLAG_RESTORED_APP_TYPE = 0B0011110000;
/**
@@ -234,7 +235,7 @@
disabledMessage = shortcutInfo.getDisabledMessage();
// TODO: Use cache for this
- LauncherAppState launcherAppState = LauncherAppState.getInstance();
+ LauncherAppState launcherAppState = LauncherAppState.getInstance(context);
Drawable unbadgedDrawable = DeepShortcutManager.getInstance(context)
.getShortcutIconDrawable(shortcutInfo,
launcherAppState.getInvariantDeviceProfile().fillResIconDpi);
@@ -248,11 +249,14 @@
protected Bitmap getBadgedIcon(Bitmap unbadgedBitmap, ShortcutInfoCompat shortcutInfo,
IconCache cache, Context context) {
- unbadgedBitmap = LauncherIcons.addShadowToIcon(unbadgedBitmap);
+ unbadgedBitmap = LauncherIcons.addShadowToIcon(unbadgedBitmap, context);
// Get the app info for the source activity.
AppInfo appInfo = new AppInfo();
appInfo.user = user;
appInfo.componentName = shortcutInfo.getActivity();
+ appInfo.intent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER)
+ .setComponent(shortcutInfo.getActivity());
cache.getTitleAndIcon(appInfo, false);
return LauncherIcons.badgeWithBitmap(unbadgedBitmap, appInfo.iconBitmap, context);
}
diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java
index 73a9f64..e68a5b0 100644
--- a/src/com/android/launcher3/UninstallDropTarget.java
+++ b/src/com/android/launcher3/UninstallDropTarget.java
@@ -4,6 +4,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherActivityInfo;
import android.net.Uri;
import android.os.Bundle;
import android.os.UserHandle;
@@ -11,7 +12,6 @@
import android.util.AttributeSet;
import android.widget.Toast;
-import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
public class UninstallDropTarget extends ButtonDropTarget {
@@ -69,7 +69,7 @@
}
}
if (intent != null) {
- LauncherActivityInfoCompat info = LauncherAppsCompat.getInstance(context)
+ LauncherActivityInfo info = LauncherAppsCompat.getInstance(context)
.resolveActivity(intent, user);
if (info != null
&& (info.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 2cb9138..89ffd31 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -104,6 +104,12 @@
public static final boolean ATLEAST_LOLLIPOP_MR1 =
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1;
+ /**
+ * Indicates if the device has a debug build. Should only be used to store additional info or
+ * add extra logging and not for changing the app behavior.
+ */
+ public static final boolean IS_DEBUG_DEVICE = Build.TYPE.toLowerCase().contains("debug");
+
// An intent extra to indicate the horizontal scroll of the wallpaper.
public static final String EXTRA_WALLPAPER_OFFSET = "com.android.launcher3.WALLPAPER_OFFSET";
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index cf6b025..1030779 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1613,8 +1613,7 @@
Utilities.THREAD_POOL_EXECUTOR.execute(new Runnable() {
@Override
public void run() {
- final Point size = LauncherAppState.getInstance()
- .getInvariantDeviceProfile().defaultWallpaperSize;
+ final Point size = LauncherAppState.getIDP(getContext()).defaultWallpaperSize;
if (size.x != mWallpaperManager.getDesiredMinimumWidth()
|| size.y != mWallpaperManager.getDesiredMinimumHeight()) {
mWallpaperManager.suggestDesiredDimensions(size.x, size.y);
diff --git a/src/com/android/launcher3/allapps/AllAppsBackgroundDrawable.java b/src/com/android/launcher3/allapps/AllAppsBackgroundDrawable.java
index bc602f3..c71bc31 100644
--- a/src/com/android/launcher3/allapps/AllAppsBackgroundDrawable.java
+++ b/src/com/android/launcher3/allapps/AllAppsBackgroundDrawable.java
@@ -23,71 +23,73 @@
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-
import android.view.Gravity;
+
import com.android.launcher3.R;
/**
- * A helper class to positon and orient a drawable to be drawn.
- */
-class TransformedImageDrawable {
- private Drawable mImage;
- private float mXPercent;
- private float mYPercent;
- private int mGravity;
- private int mAlpha;
-
- /**
- * @param gravity If one of the Gravity center values, the x and y offset will take the width
- * and height of the image into account to center the image to the offset.
- */
- public TransformedImageDrawable(Resources res, int resourceId, float xPct, float yPct,
- int gravity) {
- mImage = res.getDrawable(resourceId);
- mXPercent = xPct;
- mYPercent = yPct;
- mGravity = gravity;
- }
-
- public void setAlpha(int alpha) {
- mImage.setAlpha(alpha);
- mAlpha = alpha;
- }
-
- public int getAlpha() {
- return mAlpha;
- }
-
- public void updateBounds(Rect bounds) {
- int width = mImage.getIntrinsicWidth();
- int height = mImage.getIntrinsicHeight();
- int left = bounds.left + (int) (mXPercent * bounds.width());
- int top = bounds.top + (int) (mYPercent * bounds.height());
- if ((mGravity & Gravity.CENTER_HORIZONTAL) == Gravity.CENTER_HORIZONTAL) {
- left -= (width / 2);
- }
- if ((mGravity & Gravity.CENTER_VERTICAL) == Gravity.CENTER_VERTICAL) {
- top -= (height / 2);
- }
- mImage.setBounds(left, top, left + width, top + height);
- }
-
- public void draw(Canvas canvas) {
- int c = canvas.save(Canvas.MATRIX_SAVE_FLAG);
- mImage.draw(canvas);
- canvas.restoreToCount(c);
- }
-}
-
-/**
* This is a custom composite drawable that has a fixed virtual size and dynamically lays out its
* children images relatively within its bounds. This way, we can reduce the memory usage of a
* single, large sparsely populated image.
*/
public class AllAppsBackgroundDrawable extends Drawable {
- private final TransformedImageDrawable mHand;
- private final TransformedImageDrawable[] mIcons;
+ /**
+ * A helper class to positon and orient a drawable to be drawn.
+ */
+ protected static class TransformedImageDrawable {
+ private Drawable mImage;
+ private float mXPercent;
+ private float mYPercent;
+ private int mGravity;
+ private int mAlpha;
+
+ /**
+ * @param gravity If one of the Gravity center values, the x and y offset will take the width
+ * and height of the image into account to center the image to the offset.
+ */
+ public TransformedImageDrawable(Resources res, int resourceId, float xPct, float yPct,
+ int gravity) {
+ mImage = res.getDrawable(resourceId);
+ mXPercent = xPct;
+ mYPercent = yPct;
+ mGravity = gravity;
+ }
+
+ public void setAlpha(int alpha) {
+ mImage.setAlpha(alpha);
+ mAlpha = alpha;
+ }
+
+ public int getAlpha() {
+ return mAlpha;
+ }
+
+ public void updateBounds(Rect bounds) {
+ int width = mImage.getIntrinsicWidth();
+ int height = mImage.getIntrinsicHeight();
+ int left = bounds.left + (int) (mXPercent * bounds.width());
+ int top = bounds.top + (int) (mYPercent * bounds.height());
+ if ((mGravity & Gravity.CENTER_HORIZONTAL) == Gravity.CENTER_HORIZONTAL) {
+ left -= (width / 2);
+ }
+ if ((mGravity & Gravity.CENTER_VERTICAL) == Gravity.CENTER_VERTICAL) {
+ top -= (height / 2);
+ }
+ mImage.setBounds(left, top, left + width, top + height);
+ }
+
+ public void draw(Canvas canvas) {
+ mImage.draw(canvas);
+ }
+
+ public Rect getBounds() {
+ return mImage.getBounds();
+ }
+ }
+
+ protected final TransformedImageDrawable mHand;
+ protected final TransformedImageDrawable[] mIcons;
private final int mWidth;
private final int mHeight;
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 10d4c15..a41d832 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -22,6 +22,7 @@
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.SparseIntArray;
+import android.view.MotionEvent;
import android.view.View;
import com.android.launcher3.BaseRecyclerView;
@@ -29,6 +30,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
+import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import java.util.List;
@@ -207,7 +209,8 @@
if (mApps.hasNoFilteredResults()) {
if (mEmptySearchBackground == null) {
- mEmptySearchBackground = new AllAppsBackgroundDrawable(getContext());
+ mEmptySearchBackground = DrawableFactory.get(getContext())
+ .getAllAppsBackground(getContext());
mEmptySearchBackground.setAlpha(0);
mEmptySearchBackground.setCallback(this);
updateEmptySearchBackgroundBounds();
@@ -220,6 +223,16 @@
}
}
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent e) {
+ boolean result = super.onInterceptTouchEvent(e);
+ if (!result && e.getAction() == MotionEvent.ACTION_DOWN
+ && mEmptySearchBackground != null && mEmptySearchBackground.getAlpha() > 0) {
+ mEmptySearchBackground.setHotspot(e.getX(), e.getY());
+ }
+ return result;
+ }
+
/**
* Maps the touch (from 0..1) to the adapter position that should be visible.
*/
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index c199fef..547ab2b 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -18,15 +18,12 @@
import android.view.animation.Interpolator;
import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
-import com.android.launcher3.shortcuts.DeepShortcutsContainer;
-import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.TouchController;
@@ -88,7 +85,6 @@
private static final float RECATCH_REJECTION_FRACTION = .0875f;
- private int mBezelSwipeUpHeight;
private long mAnimationDuration;
private AnimatorSet mCurrentAnimation;
@@ -104,8 +100,6 @@
mDetector.setListener(this);
mShiftRange = DEFAULT_SHIFT_RANGE;
mProgress = 1f;
- mBezelSwipeUpHeight = l.getResources().getDimensionPixelSize(
- R.dimen.all_apps_bezel_swipe_height);
mEvaluator = new ArgbEvaluator();
mAllAppsBackgroundColor = ContextCompat.getColor(l, R.color.all_apps_container_color);
@@ -120,8 +114,6 @@
} else if (mLauncher.isAllAppsVisible() &&
!mAppsView.shouldContainerScroll(ev)) {
mNoIntercept = true;
- } else if (!mLauncher.isAllAppsVisible() && !shouldPossiblyIntercept(ev)) {
- mNoIntercept = true;
} else if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
mNoIntercept = true;
} else {
@@ -150,6 +142,7 @@
ignoreSlopWhenSettling);
}
}
+
if (mNoIntercept) {
return false;
}
@@ -160,25 +153,6 @@
return mDetector.isDraggingOrSettling();
}
- private boolean shouldPossiblyIntercept(MotionEvent ev) {
- DeviceProfile grid = mLauncher.getDeviceProfile();
- if (mDetector.isIdleState()) {
- if (grid.isVerticalBarLayout()) {
- if (ev.getY() > mLauncher.getDeviceProfile().heightPx - mBezelSwipeUpHeight) {
- return true;
- }
- } else {
- if (mLauncher.getDragLayer().isEventOverHotseat(ev) ||
- mLauncher.getDragLayer().isEventOverPageIndicator(ev)) {
- return true;
- }
- }
- return false;
- } else {
- return true;
- }
- }
-
@Override
public boolean onControllerTouchEvent(MotionEvent ev) {
return mDetector.onTouchEvent(ev);
diff --git a/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java b/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java
deleted file mode 100644
index 830b60a..0000000
--- a/src/com/android/launcher3/compat/LauncherActivityInfoCompat.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.compat;
-
-import android.content.ComponentName;
-import android.content.pm.ApplicationInfo;
-import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
-
-public abstract class LauncherActivityInfoCompat {
-
- LauncherActivityInfoCompat() {
- }
-
- public abstract ComponentName getComponentName();
- public abstract UserHandle getUser();
- public abstract CharSequence getLabel();
- public abstract Drawable getIcon(int density);
- public abstract ApplicationInfo getApplicationInfo();
- public abstract long getFirstInstallTime();
-}
diff --git a/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java b/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java
deleted file mode 100644
index c3b9592..0000000
--- a/src/com/android/launcher3/compat/LauncherActivityInfoCompatVL.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.compat;
-
-import android.content.ComponentName;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.LauncherActivityInfo;
-import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
-
-public class LauncherActivityInfoCompatVL extends LauncherActivityInfoCompat {
- private LauncherActivityInfo mLauncherActivityInfo;
-
- LauncherActivityInfoCompatVL(LauncherActivityInfo launcherActivityInfo) {
- super();
- mLauncherActivityInfo = launcherActivityInfo;
- }
-
- public ComponentName getComponentName() {
- return mLauncherActivityInfo.getComponentName();
- }
-
- public UserHandle getUser() {
- return mLauncherActivityInfo.getUser();
- }
-
- public CharSequence getLabel() {
- return mLauncherActivityInfo.getLabel();
- }
-
- public Drawable getIcon(int density) {
- return mLauncherActivityInfo.getIcon(density);
- }
-
- public ApplicationInfo getApplicationInfo() {
- return mLauncherActivityInfo.getApplicationInfo();
- }
-
- public long getFirstInstallTime() {
- return mLauncherActivityInfo.getFirstInstallTime();
- }
-}
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java
index 73ab36c..5c6eef8 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompat.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java
@@ -19,6 +19,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.LauncherActivityInfo;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.UserHandle;
@@ -56,9 +57,9 @@
}
}
- public abstract List<LauncherActivityInfoCompat> getActivityList(String packageName,
+ public abstract List<LauncherActivityInfo> getActivityList(String packageName,
UserHandle user);
- public abstract LauncherActivityInfoCompat resolveActivity(Intent intent,
+ public abstract LauncherActivityInfo resolveActivity(Intent intent,
UserHandle user);
public abstract void startActivityForProfile(ComponentName component, UserHandle user,
Rect sourceBounds, Bundle opts);
diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
index 60f9fab..e2739c1 100644
--- a/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
+++ b/src/com/android/launcher3/compat/LauncherAppsCompatVL.java
@@ -29,7 +29,6 @@
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -45,26 +44,13 @@
}
@Override
- public List<LauncherActivityInfoCompat> getActivityList(String packageName, UserHandle user) {
- List<LauncherActivityInfo> list = mLauncherApps.getActivityList(packageName, user);
- if (list.size() == 0) {
- return Collections.emptyList();
- }
- ArrayList<LauncherActivityInfoCompat> compatList = new ArrayList<>(list.size());
- for (LauncherActivityInfo info : list) {
- compatList.add(new LauncherActivityInfoCompatVL(info));
- }
- return compatList;
+ public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
+ return mLauncherApps.getActivityList(packageName, user);
}
@Override
- public LauncherActivityInfoCompat resolveActivity(Intent intent, UserHandle user) {
- LauncherActivityInfo activity = mLauncherApps.resolveActivity(intent, user);
- if (activity != null) {
- return new LauncherActivityInfoCompatVL(activity);
- } else {
- return null;
- }
+ public LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
+ return mLauncherApps.resolveActivity(intent, user);
}
@Override
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
index 953d93d..b87582f 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
@@ -42,7 +42,7 @@
PackageInstallerCompatVL(Context context) {
mInstaller = context.getPackageManager().getPackageInstaller();
- mCache = LauncherAppState.getInstance().getIconCache();
+ mCache = LauncherAppState.getInstance(context).getIconCache();
mWorker = new Handler(LauncherModel.getWorkerLooper());
mInstaller.registerSessionCallback(mCallback, mWorker);
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 4c12032..4a2a735 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -96,9 +96,7 @@
public FolderPagedView(Context context, AttributeSet attrs) {
super(context, attrs);
- LauncherAppState app = LauncherAppState.getInstance();
-
- InvariantDeviceProfile profile = app.getInvariantDeviceProfile();
+ InvariantDeviceProfile profile = LauncherAppState.getIDP(context);
mMaxCountX = profile.numFolderColumns;
mMaxCountY = profile.numFolderRows;
diff --git a/src/com/android/launcher3/graphics/DrawableFactory.java b/src/com/android/launcher3/graphics/DrawableFactory.java
index f6a4b84..693df7a 100644
--- a/src/com/android/launcher3/graphics/DrawableFactory.java
+++ b/src/com/android/launcher3/graphics/DrawableFactory.java
@@ -23,6 +23,7 @@
import com.android.launcher3.ItemInfo;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.AllAppsBackgroundDrawable;
/**
* Factory for creating new drawables.
@@ -50,4 +51,8 @@
d.setFilterBitmap(true);
return d;
}
+
+ public AllAppsBackgroundDrawable getAllAppsBackground(Context context) {
+ return new AllAppsBackgroundDrawable(context);
+ }
}
diff --git a/src/com/android/launcher3/graphics/IconNormalizer.java b/src/com/android/launcher3/graphics/IconNormalizer.java
index 1410917..70b3dd6 100644
--- a/src/com/android/launcher3/graphics/IconNormalizer.java
+++ b/src/com/android/launcher3/graphics/IconNormalizer.java
@@ -16,6 +16,7 @@
package com.android.launcher3.graphics;
+import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -53,9 +54,9 @@
private final float[] mLeftBorder;
private final float[] mRightBorder;
- private IconNormalizer() {
+ private IconNormalizer(Context context) {
// Use twice the icon size as maximum size to avoid scaling down twice.
- mMaxSize = LauncherAppState.getInstance().getInvariantDeviceProfile().iconBitmapSize * 2;
+ mMaxSize = LauncherAppState.getIDP(context).iconBitmapSize * 2;
mBitmap = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ALPHA_8);
mCanvas = new Canvas(mBitmap);
mPixels = new byte[mMaxSize * mMaxSize];
@@ -239,10 +240,10 @@
}
}
- public static IconNormalizer getInstance() {
+ public static IconNormalizer getInstance(Context context) {
synchronized (LOCK) {
if (sIconNormalizer == null) {
- sIconNormalizer = new IconNormalizer();
+ sIconNormalizer = new IconNormalizer(context);
}
}
return sIconNormalizer;
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index 48f376f..8d8f3d9 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -20,9 +20,7 @@
import android.content.Intent.ShortcutIconResource;
import android.content.pm.PackageManager;
import android.content.res.Resources;
-import android.database.Cursor;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
@@ -55,16 +53,6 @@
Paint.FILTER_BITMAP_FLAG));
}
-
- public static Bitmap createIconBitmap(Cursor c, int iconIndex, Context context) {
- byte[] data = c.getBlob(iconIndex);
- try {
- return createIconBitmap(BitmapFactory.decodeByteArray(data, 0, data.length), context);
- } catch (Exception e) {
- return null;
- }
- }
-
/**
* Returns a bitmap suitable for the all apps view. If the package or the resource do not
* exist, it returns null.
@@ -76,9 +64,8 @@
Resources resources = packageManager.getResourcesForApplication(iconRes.packageName);
if (resources != null) {
final int id = resources.getIdentifier(iconRes.resourceName, null, null);
- return createIconBitmap(
- resources.getDrawableForDensity(id, LauncherAppState.getInstance()
- .getInvariantDeviceProfile().fillResIconDpi), context);
+ return createIconBitmap(resources.getDrawableForDensity(
+ id, LauncherAppState.getIDP(context).fillResIconDpi), context);
}
} catch (Exception e) {
// Icon not found.
@@ -86,15 +73,11 @@
return null;
}
- private static int getIconBitmapSize() {
- return LauncherAppState.getInstance().getInvariantDeviceProfile().iconBitmapSize;
- }
-
/**
* Returns a bitmap which is of the appropriate size to be displayed as an icon
*/
public static Bitmap createIconBitmap(Bitmap icon, Context context) {
- final int iconBitmapSize = getIconBitmapSize();
+ final int iconBitmapSize = LauncherAppState.getIDP(context).iconBitmapSize;
if (iconBitmapSize == icon.getWidth() && iconBitmapSize == icon.getHeight()) {
return icon;
}
@@ -108,7 +91,7 @@
public static Bitmap createBadgedIconBitmap(
Drawable icon, UserHandle user, Context context) {
float scale = FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ?
- 1 : IconNormalizer.getInstance().getScale(icon, null);
+ 1 : IconNormalizer.getInstance(context).getScale(icon, null);
Bitmap bitmap = createIconBitmap(icon, context, scale);
return badgeIconForUser(bitmap, user, context);
}
@@ -138,7 +121,7 @@
public static Bitmap createScaledBitmapWithoutShadow(Drawable icon, Context context) {
RectF iconBounds = new RectF();
float scale = FeatureFlags.LAUNCHER3_DISABLE_ICON_NORMALIZATION ?
- 1 : IconNormalizer.getInstance().getScale(icon, iconBounds);
+ 1 : IconNormalizer.getInstance(context).getScale(icon, iconBounds);
scale = Math.min(scale, ShadowGenerator.getScaleForBounds(iconBounds));
return createIconBitmap(icon, context, scale);
}
@@ -147,8 +130,8 @@
* Adds a shadow to the provided icon. It assumes that the icon has already been scaled using
* {@link #createScaledBitmapWithoutShadow(Drawable, Context)}
*/
- public static Bitmap addShadowToIcon(Bitmap icon) {
- return ShadowGenerator.getInstance().recreateIcon(icon);
+ public static Bitmap addShadowToIcon(Bitmap icon, Context context) {
+ return ShadowGenerator.getInstance(context).recreateIcon(icon);
}
/**
@@ -180,7 +163,7 @@
public static Bitmap createIconBitmap(Drawable icon, Context context, float scale) {
icon = castToMaskableIconDrawable(icon);
synchronized (sCanvas) {
- final int iconBitmapSize = getIconBitmapSize();
+ final int iconBitmapSize = LauncherAppState.getIDP(context).iconBitmapSize;
int width = iconBitmapSize;
int height = iconBitmapSize;
diff --git a/src/com/android/launcher3/graphics/ShadowGenerator.java b/src/com/android/launcher3/graphics/ShadowGenerator.java
index 2b24ec9..8aea5a0 100644
--- a/src/com/android/launcher3/graphics/ShadowGenerator.java
+++ b/src/com/android/launcher3/graphics/ShadowGenerator.java
@@ -16,6 +16,7 @@
package com.android.launcher3.graphics;
+import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BlurMaskFilter;
@@ -52,8 +53,8 @@
private final Paint mBlurPaint;
private final Paint mDrawPaint;
- private ShadowGenerator() {
- mIconSize = LauncherAppState.getInstance().getInvariantDeviceProfile().iconBitmapSize;
+ private ShadowGenerator(Context context) {
+ mIconSize = LauncherAppState.getIDP(context).iconBitmapSize;
mCanvas = new Canvas();
mBlurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
mBlurPaint.setMaskFilter(new BlurMaskFilter(mIconSize * BLUR_FACTOR, Blur.NORMAL));
@@ -82,11 +83,11 @@
return result;
}
- public static ShadowGenerator getInstance() {
+ public static ShadowGenerator getInstance(Context context) {
Preconditions.assertNonUiThread();
synchronized (LOCK) {
if (sShadowGenerator == null) {
- sShadowGenerator = new ShadowGenerator();
+ sShadowGenerator = new ShadowGenerator(context);
}
}
return sShadowGenerator;
diff --git a/src/com/android/launcher3/logging/FileLog.java b/src/com/android/launcher3/logging/FileLog.java
index 8629e92..ffb41b7 100644
--- a/src/com/android/launcher3/logging/FileLog.java
+++ b/src/com/android/launcher3/logging/FileLog.java
@@ -40,7 +40,7 @@
private static File sLogsDirectory = null;
public static void setDir(File logsDir) {
- if (ProviderConfig.IS_DOGFOOD_BUILD) {
+ if (ProviderConfig.IS_DOGFOOD_BUILD || Utilities.IS_DEBUG_DEVICE) {
synchronized (DATE_FORMAT) {
// If the target directory changes, stop any active thread.
if (sHandler != null && !logsDir.equals(sLogsDirectory)) {
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 6dc5a36..2ac33ea 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -99,11 +99,11 @@
deepShortcutMap.clear();
}
- public synchronized void removeItem(ItemInfo... items) {
- removeItem(Arrays.asList(items));
+ public synchronized void removeItem(Context context, ItemInfo... items) {
+ removeItem(context, Arrays.asList(items));
}
- public synchronized void removeItem(Iterable<? extends ItemInfo> items) {
+ public synchronized void removeItem(Context context, Iterable<? extends ItemInfo> items) {
for (ItemInfo item : items) {
switch (item.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
@@ -125,7 +125,6 @@
// Decrement pinned shortcut count
ShortcutKey pinnedShortcut = ShortcutKey.fromItemInfo(item);
MutableInt count = pinnedShortcutCounts.get(pinnedShortcut);
- Context context = LauncherAppState.getInstance().getContext();
if ((count == null || --count.value == 0)
&& !InstallShortcutReceiver.getPendingShortcuts(context)
.contains(pinnedShortcut)) {
@@ -146,7 +145,7 @@
}
}
- public synchronized void addItem(ItemInfo item, boolean newItem) {
+ public synchronized void addItem(Context context, ItemInfo item, boolean newItem) {
itemsIdMap.put(item.id, item);
switch (item.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
@@ -166,8 +165,7 @@
// Since this is a new item, pin the shortcut in the system server.
if (newItem && count.value == 1) {
- DeepShortcutManager.getInstance(LauncherAppState.getInstance().getContext())
- .pinShortcut(pinnedShortcut);
+ DeepShortcutManager.getInstance(context).pinShortcut(pinnedShortcut);
}
// Fall through
}
diff --git a/src/com/android/launcher3/model/GridSizeMigrationTask.java b/src/com/android/launcher3/model/GridSizeMigrationTask.java
index 599dcd0..bbc7ae4 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationTask.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationTask.java
@@ -895,7 +895,7 @@
*/
public static boolean migrateGridIfNeeded(Context context) {
SharedPreferences prefs = Utilities.getPrefs(context);
- InvariantDeviceProfile idp = LauncherAppState.getInstance().getInvariantDeviceProfile();
+ InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
String gridSizeString = getPointString(idp.numColumns, idp.numRows);
@@ -915,8 +915,7 @@
if (srcHotseatCount != idp.numHotseatIcons) {
// Migrate hotseat.
- dbChanged = new GridSizeMigrationTask(context,
- LauncherAppState.getInstance().getInvariantDeviceProfile(),
+ dbChanged = new GridSizeMigrationTask(context, LauncherAppState.getIDP(context),
validPackages, srcHotseatCount, idp.numHotseatIcons).migrateHotseat();
}
@@ -978,9 +977,9 @@
* @return a map with occupied hotseat position set to non-null value.
*/
public static LongArrayMap<Object> removeBrokenHotseatItems(Context context) throws Exception {
- GridSizeMigrationTask task = new GridSizeMigrationTask(context,
- LauncherAppState.getInstance().getInvariantDeviceProfile(),
- getValidPackages(context), Integer.MAX_VALUE, Integer.MAX_VALUE);
+ GridSizeMigrationTask task = new GridSizeMigrationTask(
+ context, LauncherAppState.getIDP(context), getValidPackages(context),
+ Integer.MAX_VALUE, Integer.MAX_VALUE);
// Load all the valid entries
ArrayList<DbEntry> items = task.loadHotseatEntries();
@@ -1038,8 +1037,7 @@
}
protected boolean runStepTask(Point sourceSize, Point nextSize) throws Exception {
- return new GridSizeMigrationTask(mContext,
- LauncherAppState.getInstance().getInvariantDeviceProfile(),
+ return new GridSizeMigrationTask(mContext, LauncherAppState.getIDP(mContext),
mValidPackages, sourceSize, nextSize).migrateWorkspace();
}
}
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
new file mode 100644
index 0000000..43e1bd6
--- /dev/null
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model;
+
+import android.content.ComponentName;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.Intent.ShortcutIconResource;
+import android.content.pm.LauncherActivityInfo;
+import android.database.Cursor;
+import android.database.CursorWrapper;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.UserHandle;
+import android.provider.BaseColumns;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.LongSparseArray;
+
+import com.android.launcher3.IconCache;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.Workspace;
+import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.graphics.LauncherIcons;
+import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.util.ContentWriter;
+import com.android.launcher3.util.GridOccupancy;
+import com.android.launcher3.util.LongArrayMap;
+import com.android.launcher3.util.PackageManagerHelper;
+
+import java.security.InvalidParameterException;
+import java.util.ArrayList;
+
+/**
+ * Extension of {@link Cursor} with utility methods for workspace loading.
+ */
+public class LoaderCursor extends CursorWrapper {
+
+ private static final String TAG = "LoaderCursor";
+
+ public final LongSparseArray<UserHandle> allUsers = new LongSparseArray<>();
+
+ private final Context mContext;
+ private final UserManagerCompat mUserManager;
+ private final IconCache mIconCache;
+ private final InvariantDeviceProfile mIDP;
+
+ private final ArrayList<Long> itemsToRemove = new ArrayList<>();
+ private final ArrayList<Long> restoredRows = new ArrayList<>();
+ private final LongArrayMap<GridOccupancy> occupied = new LongArrayMap<>();
+
+ private final int iconPackageIndex;
+ private final int iconResourceIndex;
+ private final int iconIndex;
+ public final int titleIndex;
+
+ private final int idIndex;
+ private final int containerIndex;
+ private final int itemTypeIndex;
+ private final int screenIndex;
+ private final int cellXIndex;
+ private final int cellYIndex;
+ private final int profileIdIndex;
+
+ // Properties loaded per iteration
+ public long serialNumber;
+ public UserHandle user;
+ public long id;
+ public long container;
+ public int itemType;
+
+ public LoaderCursor(Cursor c, LauncherAppState app) {
+ super(c);
+ mContext = app.getContext();
+ mIconCache = app.getIconCache();
+ mIDP = app.getInvariantDeviceProfile();
+ mUserManager = UserManagerCompat.getInstance(mContext);
+
+ // Init column indices
+ iconIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
+ iconPackageIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
+ iconResourceIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
+ titleIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
+
+ idIndex = getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
+ containerIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER);
+ itemTypeIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
+ screenIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN);
+ cellXIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX);
+ cellYIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY);
+ profileIdIndex = getColumnIndexOrThrow(LauncherSettings.Favorites.PROFILE_ID);
+ }
+
+ @Override
+ public boolean moveToNext() {
+ boolean result = super.moveToNext();
+ if (result) {
+ // Load common properties.
+ itemType = getInt(itemTypeIndex);
+ container = getInt(containerIndex);
+ id = getLong(idIndex);
+ serialNumber = getInt(profileIdIndex);
+ user = allUsers.get(serialNumber);
+ }
+ return result;
+ }
+
+ public ShortcutInfo loadSimpleShortcut() {
+ final ShortcutInfo info = new ShortcutInfo();
+ // Non-app shortcuts are only supported for current user.
+ info.user = user;
+ info.itemType = itemType;
+ info.title = getTitle();
+ info.iconBitmap = loadIcon(info);
+ // the fallback icon
+ if (info.iconBitmap == null) {
+ info.iconBitmap = mIconCache.getDefaultIcon(info.user);
+ }
+
+ // TODO: If there's an explicit component and we can't install that, delete it.
+
+ return info;
+ }
+
+ /**
+ * Loads the icon from the cursor and updates the {@param info} if the icon is an app resource.
+ */
+ protected Bitmap loadIcon(ShortcutInfo info) {
+ Bitmap icon = null;
+ if (itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) {
+ String packageName = getString(iconPackageIndex);
+ String resourceName = getString(iconResourceIndex);
+ if (!TextUtils.isEmpty(packageName) || !TextUtils.isEmpty(resourceName)) {
+ info.iconResource = new ShortcutIconResource();
+ info.iconResource.packageName = packageName;
+ info.iconResource.resourceName = resourceName;
+ icon = LauncherIcons.createIconBitmap(info.iconResource, mContext);
+ }
+ }
+ if (icon == null) {
+ // Failed to load from resource, try loading from DB.
+ byte[] data = getBlob(iconIndex);
+ try {
+ icon = LauncherIcons.createIconBitmap(
+ BitmapFactory.decodeByteArray(data, 0, data.length), mContext);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+ return icon;
+ }
+
+ /**
+ * Returns the title or empty string
+ */
+ private String getTitle() {
+ String title = getString(titleIndex);
+ return TextUtils.isEmpty(title) ? "" : Utilities.trim(title);
+ }
+
+
+ /**
+ * Make an ShortcutInfo object for a restored application or shortcut item that points
+ * to a package that is not yet installed on the system.
+ */
+ public ShortcutInfo getRestoredItemInfo(Intent intent, int promiseType) {
+ final ShortcutInfo info = new ShortcutInfo();
+ info.user = user;
+ info.promisedIntent = intent;
+
+ info.iconBitmap = loadIcon(info);
+ // the fallback icon
+ if (info.iconBitmap == null) {
+ mIconCache.getTitleAndIcon(info, false /* useLowResIcon */);
+ }
+
+ if ((promiseType & ShortcutInfo.FLAG_RESTORED_ICON) != 0) {
+ String title = getTitle();
+ if (!TextUtils.isEmpty(title)) {
+ info.title = Utilities.trim(title);
+ }
+ } else if ((promiseType & ShortcutInfo.FLAG_AUTOINTALL_ICON) != 0) {
+ if (TextUtils.isEmpty(info.title)) {
+ info.title = getTitle();
+ }
+ } else {
+ throw new InvalidParameterException("Invalid restoreType " + promiseType);
+ }
+
+ info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);
+ info.itemType = itemType;
+ info.status = promiseType;
+ return info;
+ }
+
+ /**
+ * Make an ShortcutInfo object for a shortcut that is an application.
+ */
+ public ShortcutInfo getAppShortcutInfo(
+ Intent intent, boolean allowMissingTarget, boolean useLowResIcon) {
+ if (user == null) {
+ Log.d(TAG, "Null user found in getShortcutInfo");
+ return null;
+ }
+
+ ComponentName componentName = intent.getComponent();
+ if (componentName == null) {
+ Log.d(TAG, "Missing component found in getShortcutInfo");
+ return null;
+ }
+
+ Intent newIntent = new Intent(Intent.ACTION_MAIN, null);
+ newIntent.addCategory(Intent.CATEGORY_LAUNCHER);
+ newIntent.setComponent(componentName);
+ LauncherActivityInfo lai = LauncherAppsCompat.getInstance(mContext)
+ .resolveActivity(newIntent, user);
+ if ((lai == null) && !allowMissingTarget) {
+ Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName);
+ return null;
+ }
+
+ final ShortcutInfo info = new ShortcutInfo();
+ info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+ info.user = user;
+ info.intent = newIntent;
+
+ mIconCache.getTitleAndIcon(info, lai, useLowResIcon);
+ if (mIconCache.isDefaultIcon(info.iconBitmap, user)) {
+ Bitmap icon = loadIcon(info);
+ info.iconBitmap = icon != null ? icon : info.iconBitmap;
+ }
+
+ if (lai != null && PackageManagerHelper.isAppSuspended(lai.getApplicationInfo())) {
+ info.isDisabled = ShortcutInfo.FLAG_DISABLED_SUSPENDED;
+ }
+
+ // from the db
+ if (TextUtils.isEmpty(info.title)) {
+ info.title = getTitle();
+ }
+
+ // fall back to the class name of the activity
+ if (info.title == null) {
+ info.title = componentName.getClassName();
+ }
+
+ info.contentDescription = mUserManager.getBadgedLabelForUser(info.title, info.user);
+ return info;
+ }
+
+ /**
+ * Returns a {@link ContentWriter} which can be used to update the current item.
+ */
+ public ContentWriter updater() {
+ return new ContentWriter(mContext, new ContentWriter.CommitParams(
+ BaseColumns._ID + "= ?", new String[]{Long.toString(id)}));
+ }
+
+ /**
+ * Marks the current item for removal
+ */
+ public void markDeleted(String reason) {
+ FileLog.e(TAG, reason);
+ itemsToRemove.add(id);
+ }
+
+ /**
+ * Removes any items marked for removal.
+ * @return true is any item was removed.
+ */
+ public boolean commitDeleted() {
+ if (itemsToRemove.size() > 0) {
+ // Remove dead items
+ mContext.getContentResolver().delete(LauncherSettings.Favorites.CONTENT_URI,
+ Utilities.createDbSelectionQuery(
+ LauncherSettings.Favorites._ID, itemsToRemove), null);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Marks the current item as restored
+ */
+ public void markRestored() {
+ restoredRows.add(id);
+ }
+
+ public void commitRestoredItems() {
+ if (restoredRows.size() > 0) {
+ // Update restored items that no longer require special handling
+ ContentValues values = new ContentValues();
+ values.put(LauncherSettings.Favorites.RESTORED, 0);
+ mContext.getContentResolver().update(LauncherSettings.Favorites.CONTENT_URI, values,
+ Utilities.createDbSelectionQuery(
+ LauncherSettings.Favorites._ID, restoredRows), null);
+ }
+ }
+
+ /**
+ * Returns true is the item is on workspace or hotseat
+ */
+ public boolean isOnWorkspaceOrHotseat() {
+ return container == LauncherSettings.Favorites.CONTAINER_DESKTOP ||
+ container == LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+ }
+
+ /**
+ * Applies the following properties:
+ * {@link ItemInfo#id}
+ * {@link ItemInfo#container}
+ * {@link ItemInfo#screenId}
+ * {@link ItemInfo#cellX}
+ * {@link ItemInfo#cellY}
+ */
+ public void applyCommonProperties(ItemInfo info) {
+ info.id = id;
+ info.container = container;
+ info.screenId = getInt(screenIndex);
+ info.cellX = getInt(cellXIndex);
+ info.cellY = getInt(cellYIndex);
+ }
+
+ /**
+ * Adds the {@param info} to {@param dataModel} if it does not overlap with any other item,
+ * otherwise marks it for deletion.
+ */
+ public void checkAndAddItem(ItemInfo info, BgDataModel dataModel) {
+ if (checkItemPlacement(info, dataModel.workspaceScreens)) {
+ dataModel.addItem(mContext, info, false);
+ } else {
+ markDeleted("Item position overlap");
+ }
+ }
+
+ /**
+ * check & update map of what's occupied; used to discard overlapping/invalid items
+ */
+ protected boolean checkItemPlacement(ItemInfo item, ArrayList<Long> workspaceScreens) {
+ long containerIndex = item.screenId;
+ if (item.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+ // Return early if we detect that an item is under the hotseat button
+ if (!FeatureFlags.NO_ALL_APPS_ICON &&
+ mIDP.isAllAppsButtonRank((int) item.screenId)) {
+ Log.e(TAG, "Error loading shortcut into hotseat " + item
+ + " into position (" + item.screenId + ":" + item.cellX + ","
+ + item.cellY + ") occupied by all apps");
+ return false;
+ }
+
+ final GridOccupancy hotseatOccupancy =
+ occupied.get((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT);
+
+ if (item.screenId >= mIDP.numHotseatIcons) {
+ Log.e(TAG, "Error loading shortcut " + item
+ + " into hotseat position " + item.screenId
+ + ", position out of bounds: (0 to " + (mIDP.numHotseatIcons - 1)
+ + ")");
+ return false;
+ }
+
+ if (hotseatOccupancy != null) {
+ if (hotseatOccupancy.cells[(int) item.screenId][0]) {
+ Log.e(TAG, "Error loading shortcut into hotseat " + item
+ + " into position (" + item.screenId + ":" + item.cellX + ","
+ + item.cellY + ") already occupied");
+ return false;
+ } else {
+ hotseatOccupancy.cells[(int) item.screenId][0] = true;
+ return true;
+ }
+ } else {
+ final GridOccupancy occupancy = new GridOccupancy(mIDP.numHotseatIcons, 1);
+ occupancy.cells[(int) item.screenId][0] = true;
+ occupied.put((long) LauncherSettings.Favorites.CONTAINER_HOTSEAT, occupancy);
+ return true;
+ }
+ } else if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+ if (!workspaceScreens.contains((Long) item.screenId)) {
+ // The item has an invalid screen id.
+ return false;
+ }
+ } else {
+ // Skip further checking if it is not the hotseat or workspace container
+ return true;
+ }
+
+ final int countX = mIDP.numColumns;
+ final int countY = mIDP.numRows;
+ if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
+ item.cellX < 0 || item.cellY < 0 ||
+ item.cellX + item.spanX > countX || item.cellY + item.spanY > countY) {
+ Log.e(TAG, "Error loading shortcut " + item
+ + " into cell (" + containerIndex + "-" + item.screenId + ":"
+ + item.cellX + "," + item.cellY
+ + ") out of screen bounds ( " + countX + "x" + countY + ")");
+ return false;
+ }
+
+ if (!occupied.containsKey(item.screenId)) {
+ GridOccupancy screen = new GridOccupancy(countX + 1, countY + 1);
+ if (item.screenId == Workspace.FIRST_SCREEN_ID) {
+ // Mark the first row as occupied (if the feature is enabled)
+ // in order to account for the QSB.
+ screen.markCells(0, 0, countX + 1, 1, FeatureFlags.QSB_ON_FIRST_SCREEN);
+ }
+ occupied.put(item.screenId, screen);
+ }
+ final GridOccupancy occupancy = occupied.get(item.screenId);
+
+ // Check if any workspace icons overlap with each other
+ if (occupancy.isRegionVacant(item.cellX, item.cellY, item.spanX, item.spanY)) {
+ occupancy.markCells(item, true);
+ return true;
+ } else {
+ Log.e(TAG, "Error loading shortcut " + item
+ + " into cell (" + containerIndex + "-" + item.screenId + ":"
+ + item.cellX + "," + item.cellX + "," + item.spanX + "," + item.spanY
+ + ") already occupied");
+ return false;
+ }
+ }
+}
diff --git a/src/com/android/launcher3/model/PackageItemInfo.java b/src/com/android/launcher3/model/PackageItemInfo.java
index e05bf1e..baeaa94 100644
--- a/src/com/android/launcher3/model/PackageItemInfo.java
+++ b/src/com/android/launcher3/model/PackageItemInfo.java
@@ -28,7 +28,7 @@
*/
public String packageName;
- PackageItemInfo(String packageName) {
+ public PackageItemInfo(String packageName) {
this.packageName = packageName;
}
diff --git a/src/com/android/launcher3/model/WidgetItem.java b/src/com/android/launcher3/model/WidgetItem.java
index 452dbe2..c256176 100644
--- a/src/com/android/launcher3/model/WidgetItem.java
+++ b/src/com/android/launcher3/model/WidgetItem.java
@@ -31,16 +31,16 @@
public final String label;
public final int spanX, spanY;
- public WidgetItem(LauncherAppWidgetProviderInfo info, PackageManager pm) {
+ public WidgetItem(LauncherAppWidgetProviderInfo info, PackageManager pm,
+ InvariantDeviceProfile idp) {
super(info.provider, info.getProfile());
label = Utilities.trim(info.getLabel(pm));
widgetInfo = info;
activityInfo = null;
- InvariantDeviceProfile idv = LauncherAppState.getInstance().getInvariantDeviceProfile();
- spanX = Math.min(info.spanX, idv.numColumns);
- spanY = Math.min(info.spanY, idv.numRows);
+ spanX = Math.min(info.spanX, idp.numColumns);
+ spanY = Math.min(info.spanY, idp.numRows);
}
public WidgetItem(ResolveInfo info, PackageManager pm) {
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index 2565985..2c62f89 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -60,12 +60,13 @@
final ArrayList<WidgetItem> widgetsAndShortcuts = new ArrayList<>();
try {
PackageManager pm = context.getPackageManager();
+ InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
// Widgets
for (AppWidgetProviderInfo widgetInfo :
AppWidgetManagerCompat.getInstance(context).getAllProviders()) {
- widgetsAndShortcuts.add(new WidgetItem(
- LauncherAppWidgetProviderInfo.fromProviderInfo(context, widgetInfo), pm));
+ widgetsAndShortcuts.add(new WidgetItem(LauncherAppWidgetProviderInfo
+ .fromProviderInfo(context, widgetInfo), pm, idp));
}
// Shortcuts
@@ -73,7 +74,7 @@
pm.queryIntentActivities(new Intent(Intent.ACTION_CREATE_SHORTCUT), 0)) {
widgetsAndShortcuts.add(new WidgetItem(info, pm));
}
- setWidgetsAndShortcuts(widgetsAndShortcuts);
+ setWidgetsAndShortcuts(widgetsAndShortcuts, context);
} catch (Exception e) {
if (!ProviderConfig.IS_DOGFOOD_BUILD && Utilities.isBinderSizeError(e)) {
// the returned value may be incomplete and will not be refreshed until the next
@@ -87,7 +88,8 @@
return widgetsAndShortcuts;
}
- private void setWidgetsAndShortcuts(ArrayList<WidgetItem> rawWidgetsShortcuts) {
+ private void setWidgetsAndShortcuts(ArrayList<WidgetItem> rawWidgetsShortcuts,
+ Context context) {
if (DEBUG) {
Log.d(TAG, "addWidgetsAndShortcuts, widgetsShortcuts#=" + rawWidgetsShortcuts.size());
}
@@ -99,7 +101,7 @@
// clear the lists.
mWidgetsList.clear();
- InvariantDeviceProfile idp = LauncherAppState.getInstance().getInvariantDeviceProfile();
+ InvariantDeviceProfile idp = LauncherAppState.getIDP(context);
UserHandle myUser = Process.myUserHandle();
// add and update.
diff --git a/src/com/android/launcher3/provider/ImportDataTask.java b/src/com/android/launcher3/provider/ImportDataTask.java
index 9d8e62a..b0482f8 100644
--- a/src/com/android/launcher3/provider/ImportDataTask.java
+++ b/src/com/android/launcher3/provider/ImportDataTask.java
@@ -89,10 +89,12 @@
ArrayList<Long> allScreens = LauncherDbUtils.getScreenIdsFromCursor(
mContext.getContentResolver().query(mOtherScreensUri, null, null, null,
LauncherSettings.WorkspaceScreens.SCREEN_RANK));
+ FileLog.d(TAG, "Importing DB from " + mOtherFavoritesUri);
// During import we reset the screen IDs to 0-indexed values.
if (allScreens.isEmpty()) {
// No thing to migrate
+ FileLog.e(TAG, "No data found to import");
return false;
}
@@ -293,6 +295,7 @@
}
}
}
+ FileLog.d(TAG, totalItemsOnWorkspace + " items imported from external source");
if (totalItemsOnWorkspace < MIN_ITEM_COUNT_FOR_SUCCESSFUL_MIGRATION) {
throw new Exception("Insufficient data");
}
@@ -303,7 +306,7 @@
}
LongArrayMap<Object> hotseatItems = GridSizeMigrationTask.removeBrokenHotseatItems(mContext);
- int myHotseatCount = LauncherAppState.getInstance().getInvariantDeviceProfile().numHotseatIcons;
+ int myHotseatCount = LauncherAppState.getIDP(mContext).numHotseatIcons;
if (!FeatureFlags.NO_ALL_APPS_ICON) {
myHotseatCount--;
}
@@ -378,8 +381,8 @@
return c.getSharedPreferences(LauncherFiles.DEVICE_PREFERENCES_KEY, Context.MODE_PRIVATE);
}
- private static final int getMyHotseatLayoutId() {
- return LauncherAppState.getInstance().getInvariantDeviceProfile().numHotseatIcons <= 5
+ private static final int getMyHotseatLayoutId(Context context) {
+ return LauncherAppState.getIDP(context).numHotseatIcons <= 5
? R.xml.dw_phone_hotseat
: R.xml.dw_tablet_hotseat;
}
@@ -389,7 +392,7 @@
*/
private static class HotseatLayoutParser extends DefaultLayoutParser {
public HotseatLayoutParser(Context context, LayoutParserCallback callback) {
- super(context, null, callback, context.getResources(), getMyHotseatLayoutId());
+ super(context, null, callback, context.getResources(), getMyHotseatLayoutId(context));
}
@Override
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
index 89fd99b..1758350 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -76,8 +76,7 @@
}
}
- new LossyScreenMigrationTask(
- context, LauncherAppState.getInstance().getInvariantDeviceProfile(), db)
+ new LossyScreenMigrationTask(context, LauncherAppState.getIDP(context), db)
.migrateScreen0();
db.setTransactionSuccessful();
return true;
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 47bee06..a200a85 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -142,6 +142,7 @@
}
public static void setPending(Context context, boolean isPending) {
+ FileLog.d(TAG, "Restore data received through full backup");
Utilities.getPrefs(context).edit().putBoolean(RESTORE_TASK_PENDING, isPending).commit();
}
}
diff --git a/src/com/android/launcher3/qsb/QsbContainerView.java b/src/com/android/launcher3/qsb/QsbContainerView.java
index c83143b..38a3e1f 100644
--- a/src/com/android/launcher3/qsb/QsbContainerView.java
+++ b/src/com/android/launcher3/qsb/QsbContainerView.java
@@ -102,7 +102,7 @@
}
AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(activity);
- InvariantDeviceProfile idp = LauncherAppState.getInstance().getInvariantDeviceProfile();
+ InvariantDeviceProfile idp = LauncherAppState.getIDP(activity);
Bundle opts = new Bundle();
Rect size = AppWidgetResizeFrame.getWidgetSizeRanges(activity, idp.numColumns, 1, null);
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutView.java b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
index 6796137..04c71ec 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutView.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
@@ -34,6 +34,7 @@
import com.android.launcher3.shortcuts.DeepShortcutsContainer.UnbadgedShortcutInfo;
import com.android.launcher3.util.PillRevealOutlineProvider;
import com.android.launcher3.util.PillWidthRevealOutlineProvider;
+import com.android.launcher3.util.Provider;
/**
* A {@link android.widget.FrameLayout} that contains a {@link DeepShortcutView}.
@@ -114,10 +115,17 @@
* Returns the shortcut info that is suitable to be added on the homescreen
*/
public ShortcutInfo getFinalInfo() {
- ShortcutInfo badged = new ShortcutInfo(mInfo);
+ final ShortcutInfo badged = new ShortcutInfo(mInfo);
// Queue an update task on the worker thread. This ensures that the badged
// shortcut eventually gets its icon updated.
- Launcher.getLauncher(getContext()).getModel().updateShortcutInfo(mInfo.mDetail, badged);
+ Launcher.getLauncher(getContext()).getModel().updateAndBindShortcutInfo(
+ new Provider<ShortcutInfo>() {
+ @Override
+ public ShortcutInfo get() {
+ badged.updateFromDeepShortcutInfo(mInfo.mDetail, getContext());
+ return badged;
+ }
+ });
return badged;
}
diff --git a/src/com/android/launcher3/testing/ToggleWeightWatcher.java b/src/com/android/launcher3/testing/ToggleWeightWatcher.java
index e08ec3a..f0c3920 100644
--- a/src/com/android/launcher3/testing/ToggleWeightWatcher.java
+++ b/src/com/android/launcher3/testing/ToggleWeightWatcher.java
@@ -22,7 +22,7 @@
show = !show;
sp.edit().putBoolean(TestingUtils.SHOW_WEIGHT_WATCHER, show).apply();
- Launcher launcher = (Launcher) LauncherAppState.getInstance().getModel().getCallback();
+ Launcher launcher = (Launcher) LauncherAppState.getInstance(this).getModel().getCallback();
if (launcher != null && launcher.mWeightWatcher != null) {
launcher.mWeightWatcher.setVisibility(show ? View.VISIBLE : View.GONE);
}
diff --git a/src/com/android/launcher3/util/CachedPackageTracker.java b/src/com/android/launcher3/util/CachedPackageTracker.java
index ab5f44f..314b4c0 100644
--- a/src/com/android/launcher3/util/CachedPackageTracker.java
+++ b/src/com/android/launcher3/util/CachedPackageTracker.java
@@ -18,10 +18,10 @@
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.pm.LauncherActivityInfo;
import android.os.UserHandle;
import com.android.launcher3.Utilities;
-import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.LauncherAppsCompat.OnAppsChangedCallbackCompat;
import com.android.launcher3.compat.UserManagerCompat;
@@ -55,7 +55,7 @@
* Checks the list of user apps, and generates package event accordingly.
* {@see #onLauncherAppsAdded}, {@see #onLauncherPackageRemoved}
*/
- public void processUserApps(List<LauncherActivityInfoCompat> apps, UserHandle user) {
+ public void processUserApps(List<LauncherActivityInfo> apps, UserHandle user) {
String prefKey = INSTALLED_PACKAGES_PREFIX + mUserManager.getSerialNumberForUser(user);
HashSet<String> oldPackageSet = new HashSet<>();
final boolean userAppsExisted = getUserApps(oldPackageSet, prefKey);
@@ -64,7 +64,7 @@
HashSet<String> newPackageSet = new HashSet<>();
ArrayList<LauncherActivityInstallInfo> packagesAdded = new ArrayList<>();
- for (LauncherActivityInfoCompat info : apps) {
+ for (LauncherActivityInfo info : apps) {
String packageName = info.getComponentName().getPackageName();
newPackageSet.add(packageName);
packagesRemoved.remove(packageName);
@@ -123,10 +123,10 @@
HashSet<String> packageSet = new HashSet<>();
final boolean userAppsExisted = getUserApps(packageSet, prefKey);
if (!packageSet.contains(packageName)) {
- List<LauncherActivityInfoCompat> activities =
+ List<LauncherActivityInfo> activities =
mLauncherApps.getActivityList(packageName, user);
if (!activities.isEmpty()) {
- LauncherActivityInfoCompat activityInfo = activities.get(0);
+ LauncherActivityInfo activityInfo = activities.get(0);
packageSet.add(packageName);
mPrefs.edit().putStringSet(prefKey, packageSet).apply();
@@ -172,10 +172,10 @@
public static class LauncherActivityInstallInfo
implements Comparable<LauncherActivityInstallInfo> {
- public final LauncherActivityInfoCompat info;
+ public final LauncherActivityInfo info;
public final long installTime;
- public LauncherActivityInstallInfo(LauncherActivityInfoCompat info, long installTime) {
+ public LauncherActivityInstallInfo(LauncherActivityInfo info, long installTime) {
this.info = info;
this.installTime = installTime;
}
diff --git a/src/com/android/launcher3/util/ContentWriter.java b/src/com/android/launcher3/util/ContentWriter.java
index 1c347c0..4384328 100644
--- a/src/com/android/launcher3/util/ContentWriter.java
+++ b/src/com/android/launcher3/util/ContentWriter.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
+import android.net.Uri;
import android.os.UserHandle;
import com.android.launcher3.LauncherAppState;
@@ -35,9 +36,15 @@
private final ContentValues mValues;
private final Context mContext;
+ private CommitParams mCommitParams;
private Bitmap mIcon;
private UserHandle mUser;
+ public ContentWriter(Context context, CommitParams commitParams) {
+ this(context);
+ mCommitParams = commitParams;
+ }
+
public ContentWriter(Context context) {
this(new ContentValues(), context);
}
@@ -86,13 +93,34 @@
* Commits any pending validation and returns the final values.
* Must not be called on UI thread.
*/
- public ContentValues getValues() {
+ public ContentValues getValues(Context context) {
Preconditions.assertNonUiThread();
- if (mIcon != null && !LauncherAppState.getInstance().getIconCache()
+ if (mIcon != null && !LauncherAppState.getInstance(context).getIconCache()
.isDefaultIcon(mIcon, mUser)) {
mValues.put(LauncherSettings.Favorites.ICON, Utilities.flattenBitmap(mIcon));
mIcon = null;
}
return mValues;
}
+
+ public int commit() {
+ if (mCommitParams != null) {
+ return mContext.getContentResolver().update(mCommitParams.mUri, getValues(mContext),
+ mCommitParams.mWhere, mCommitParams.mSelectionArgs);
+ }
+ return 0;
+ }
+
+ public static final class CommitParams {
+
+ final Uri mUri = LauncherSettings.Favorites.CONTENT_URI;
+ String mWhere;
+ String[] mSelectionArgs;
+
+ public CommitParams(String where, String[] selectionArgs) {
+ mWhere = where;
+ mSelectionArgs = selectionArgs;
+ }
+
+ }
}
diff --git a/src/com/android/launcher3/util/CursorIconInfo.java b/src/com/android/launcher3/util/CursorIconInfo.java
deleted file mode 100644
index 3bc4eab..0000000
--- a/src/com/android/launcher3/util/CursorIconInfo.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.util;
-
-import android.content.Context;
-import android.content.Intent.ShortcutIconResource;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.text.TextUtils;
-
-import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.ShortcutInfo;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.graphics.LauncherIcons;
-
-/**
- * Utility class to load icon from a cursor.
- */
-public class CursorIconInfo {
- public final int iconPackageIndex;
- public final int iconResourceIndex;
- public final int iconIndex;
-
- public final int titleIndex;
-
- private final Context mContext;
-
- public CursorIconInfo(Context context, Cursor c) {
- mContext = context;
-
- iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON);
- iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_PACKAGE);
- iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_RESOURCE);
-
- titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
- }
-
- /**
- * Loads the icon from the cursor and updates the {@param info} if the icon is an app resource.
- */
- public Bitmap loadIcon(Cursor c, ShortcutInfo info) {
- Bitmap icon = null;
- String packageName = c.getString(iconPackageIndex);
- String resourceName = c.getString(iconResourceIndex);
- if (!TextUtils.isEmpty(packageName) || !TextUtils.isEmpty(resourceName)) {
- info.iconResource = new ShortcutIconResource();
- info.iconResource.packageName = packageName;
- info.iconResource.resourceName = resourceName;
- icon = LauncherIcons.createIconBitmap(info.iconResource, mContext);
- }
- if (icon == null) {
- // Failed to load from resource, try loading from DB.
- icon = loadIcon(c);
- }
- return icon;
- }
-
- /**
- * Loads the fixed bitmap from the icon if available.
- */
- public Bitmap loadIcon(Cursor c) {
- return LauncherIcons.createIconBitmap(c, iconIndex, mContext);
- }
-
- /**
- * Returns the title or empty string
- */
- public String getTitle(Cursor c) {
- String title = c.getString(titleIndex);
- return TextUtils.isEmpty(title) ? "" : Utilities.trim(c.getString(titleIndex));
- }
-}
diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
index ce42bcd..af61554 100644
--- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java
+++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.pm.LauncherActivityInfo;
import android.os.Process;
import android.os.UserHandle;
@@ -31,7 +32,6 @@
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutInfo;
-import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
@@ -72,8 +72,8 @@
private ManagedProfileHeuristic(Context context, UserHandle user) {
mContext = context;
mUser = user;
- mModel = LauncherAppState.getInstance().getModel();
- mIconCache = LauncherAppState.getInstance().getIconCache();
+ mModel = LauncherAppState.getInstance(context).getModel();
+ mIconCache = LauncherAppState.getInstance(context).getIconCache();
}
public void processPackageRemoved(String[] packages) {
@@ -92,7 +92,7 @@
}
}
- public void processUserApps(List<LauncherActivityInfoCompat> apps) {
+ public void processUserApps(List<LauncherActivityInfo> apps) {
Preconditions.assertWorkerThread();
new ManagedProfilePackageHandler().processUserApps(apps, mUser);
}
@@ -116,8 +116,9 @@
.isQuietModeEnabled(user);
for (int i = 0; i < count; i++) {
LauncherActivityInstallInfo info = apps.get(i);
- ShortcutInfo si = new AppInfo(mContext, info.info, user, mIconCache,
- quietModeEnabled, false /* useLowResIcon */).makeShortcut();
+ AppInfo appInfo = new AppInfo(mContext, info.info, user, quietModeEnabled);
+ mIconCache.getTitleAndIcon(appInfo, info.info, false /* useLowResIcon */);
+ ShortcutInfo si = appInfo.makeShortcut();
((info.installTime <= folderCreationTime) ? workFolderApps : homescreenApps).add(si);
}
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index b61d609..33a9fc6 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -23,6 +23,7 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
+import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
@@ -124,4 +125,13 @@
return false;
}
+
+ public static Intent getMarketIntent(String packageName) {
+ return new Intent(Intent.ACTION_VIEW)
+ .setData(new Uri.Builder()
+ .scheme("market")
+ .authority("details")
+ .appendQueryParameter("id", packageName)
+ .build());
+ }
}
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 310c1df..be4f635 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -87,7 +87,7 @@
mLauncher = Launcher.getLauncher(context);
mDragController = mLauncher.getDragController();
mAdapter = new WidgetsListAdapter(this, this, context);
- mIconCache = (LauncherAppState.getInstance()).getIconCache();
+ mIconCache = LauncherAppState.getInstance(context).getIconCache();
if (LOGD) {
Log.d(TAG, "WidgetsContainerView constructor");
}
@@ -303,7 +303,7 @@
private WidgetPreviewLoader getWidgetPreviewLoader() {
if (mWidgetPreviewLoader == null) {
- mWidgetPreviewLoader = LauncherAppState.getInstance().getWidgetCache();
+ mWidgetPreviewLoader = LauncherAppState.getInstance(getContext()).getWidgetCache();
}
return mWidgetPreviewLoader;
}
diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java
index f18313f..2d746d7 100644
--- a/src/com/android/launcher3/widget/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java
@@ -68,7 +68,7 @@
View.OnLongClickListener iconLongClickListener,
Context context) {
mLayoutInflater = LayoutInflater.from(context);
- mWidgetPreviewLoader = LauncherAppState.getInstance().getWidgetCache();
+ mWidgetPreviewLoader = LauncherAppState.getInstance(context).getWidgetCache();
mIndexer = new AlphabeticIndexCompat(context);
diff --git a/src_config/com/android/launcher3/config/FeatureFlags.java b/src_config/com/android/launcher3/config/FeatureFlags.java
index 99d2654..4cad836 100644
--- a/src_config/com/android/launcher3/config/FeatureFlags.java
+++ b/src_config/com/android/launcher3/config/FeatureFlags.java
@@ -37,4 +37,6 @@
public static final boolean PULLDOWN_SEARCH = false;
// When enabled the status bar may show dark icons based on the top of the wallpaper.
public static final boolean LIGHT_STATUS_BAR = false;
+ // When enabled allows to use any point on the fast scrollbar to start dragging.
+ public static final boolean LAUNCHER3_DIRECT_SCROLL = true;
}
diff --git a/tests/Android.mk b/tests/Android.mk
index 466146e..5103ced 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -17,9 +17,9 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
-#LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4
-#LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SDK_VERSION := current
LOCAL_MIN_SDK_VERSION := 21
diff --git a/tests/res/raw/cache_data_updated_task_data.txt b/tests/res/raw/cache_data_updated_task_data.txt
index 9095476..8199687 100644
--- a/tests/res/raw/cache_data_updated_task_data.txt
+++ b/tests/res/raw/cache_data_updated_task_data.txt
@@ -22,7 +22,7 @@
bgItem s itemType=1 status=1 title=app3-shrt intent=component=app3/class3 id=9
bgItem s itemType=1 status=1 title=app5-shrt intent=component=app5/class1 id=10
-allApps componentName=app1/class1
-allApps componentName=app1/class2
-allApps componentName=app2/class1
-allApps componentName=app2/class2
\ No newline at end of file
+allApps componentName=app1/class1 intent=component=app1/class1
+allApps componentName=app1/class2 intent=component=app1/class2
+allApps componentName=app2/class1 intent=component=app2/class1
+allApps componentName=app2/class2 intent=component=app2/class2
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/BindWidgetTest.java b/tests/src/com/android/launcher3/BindWidgetTest.java
index 72533e7..575b42b 100644
--- a/tests/src/com/android/launcher3/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/BindWidgetTest.java
@@ -16,7 +16,6 @@
import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.ui.LauncherInstrumentationTestCase;
import com.android.launcher3.util.ContentWriter;
-import com.android.launcher3.util.ManagedProfileHeuristic;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.WidgetHostViewLoader;
@@ -223,20 +222,9 @@
item.screenId = screenId;
item.onAddToDatabase(writer);
writer.put(LauncherSettings.Favorites._ID, item.id);
- mResolver.insert(LauncherSettings.Favorites.CONTENT_URI, writer.getValues());
+ mResolver.insert(LauncherSettings.Favorites.CONTENT_URI, writer.getValues(mTargetContext));
+ resetLoaderState();
- // Reset loader
- try {
- runTestOnUiThread(new Runnable() {
- @Override
- public void run() {
- ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mTargetContext);
- LauncherAppState.getInstance().getModel().resetLoadedState(true, true);
- }
- });
- } catch (Throwable t) {
- throw new IllegalArgumentException(t);
- }
// Launch the home activity
startLauncher();
// Verify UI
diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
index b2f0cbb..2071389 100644
--- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
+++ b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
@@ -164,7 +164,7 @@
info.cellX = x;
info.cellY = y;
info.container = LauncherSettings.Favorites.CONTAINER_DESKTOP;
- bgDataModel.addItem(info, false);
+ bgDataModel.addItem(targetContext, info, false);
}
}
return startId;
diff --git a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
index f23a574..9b7fc6e 100644
--- a/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
+++ b/tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
@@ -3,15 +3,18 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.LauncherActivityInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.os.Process;
import android.os.UserHandle;
+import android.support.annotation.NonNull;
import android.support.test.InstrumentationRegistry;
import android.test.ProviderTestCase2;
import com.android.launcher3.AllAppsList;
+import com.android.launcher3.AppFilter;
import com.android.launcher3.AppInfo;
import com.android.launcher3.DeferredHandler;
import com.android.launcher3.IconCache;
@@ -21,9 +24,9 @@
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherModel.BaseModelUpdateTask;
import com.android.launcher3.LauncherModel.Callbacks;
-import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.config.ProviderConfig;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.Provider;
import com.android.launcher3.util.TestLauncherProvider;
import org.mockito.ArgumentCaptor;
@@ -74,7 +77,7 @@
idp = new InvariantDeviceProfile();
iconCache = new MyIconCache(targetContext, idp);
- allAppsList = new AllAppsList(iconCache, null);
+ allAppsList = new AllAppsList(iconCache, new AppFilter());
when(appState.getIconCache()).thenReturn(iconCache);
when(appState.getInvariantDeviceProfile()).thenReturn(idp);
@@ -125,11 +128,11 @@
classMap.put(commands[1], Class.forName(commands[2]));
break;
case "bgItem":
- bgDataModel.addItem(
+ bgDataModel.addItem(targetContext,
(ItemInfo) initItem(classMap.get(commands[1]), commands, 2), false);
break;
case "allApps":
- allAppsList.add((AppInfo) initItem(AppInfo.class, commands, 1));
+ allAppsList.add((AppInfo) initItem(AppInfo.class, commands, 1), null);
break;
}
}
@@ -184,9 +187,10 @@
}
@Override
- protected CacheEntry cacheLocked(ComponentName componentName,
- LauncherActivityInfoCompat info, UserHandle user,
- boolean usePackageIcon, boolean useLowResIcon) {
+ protected CacheEntry cacheLocked(
+ @NonNull ComponentName componentName,
+ @NonNull Provider<LauncherActivityInfo> infoProvider,
+ UserHandle user, boolean usePackageIcon, boolean useLowResIcon) {
CacheEntry entry = mCache.get(new ComponentKey(componentName, user));
if (entry == null) {
entry = new CacheEntry();
@@ -205,5 +209,10 @@
public Bitmap newIcon() {
return Bitmap.createBitmap(1, 1, Config.ARGB_8888);
}
+
+ @Override
+ protected Bitmap makeDefaultIcon(UserHandle user) {
+ return newIcon();
+ }
}
}
diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index 646ef27..d595e6c 100644
--- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -30,6 +30,11 @@
}
public void testCacheUpdate_update_apps() throws Exception {
+ // Clear all icons from apps list so that its easy to check what was updated
+ for (AppInfo info : allAppsList.data) {
+ info.iconBitmap = null;
+ }
+
executeTaskForTest(newTask(CacheDataUpdatedTask.OP_CACHE_UPDATE, "app1"));
// Verify that only the app icons of app1 (id 1 & 2) are updated. Custom shortcut (id 7)
diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
new file mode 100644
index 0000000..d40e6c2
--- /dev/null
+++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java
@@ -0,0 +1,234 @@
+package com.android.launcher3.model;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.database.MatrixCursor;
+import android.graphics.Bitmap;
+import android.os.Process;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.launcher3.IconCache;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.compat.LauncherAppsCompat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import static com.android.launcher3.LauncherSettings.Favorites.CELLX;
+import static com.android.launcher3.LauncherSettings.Favorites.CELLY;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
+import static com.android.launcher3.LauncherSettings.Favorites.ICON;
+import static com.android.launcher3.LauncherSettings.Favorites.ICON_PACKAGE;
+import static com.android.launcher3.LauncherSettings.Favorites.ICON_RESOURCE;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
+import static com.android.launcher3.LauncherSettings.Favorites.PROFILE_ID;
+import static com.android.launcher3.LauncherSettings.Favorites.SCREEN;
+import static com.android.launcher3.LauncherSettings.Favorites.TITLE;
+import static com.android.launcher3.LauncherSettings.Favorites._ID;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for {@link LoaderCursor}
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class LoaderCursorTest {
+
+ private LauncherAppState mMockApp;
+ private IconCache mMockIconCache;
+
+ private MatrixCursor mCursor;
+ private InvariantDeviceProfile mIDP;
+ private Context mContext;
+ private LauncherAppsCompat mLauncherApps;
+
+ private LoaderCursor mLoaderCursor;
+
+ @Before
+ public void setup() {
+ mIDP = new InvariantDeviceProfile();
+ mCursor = new MatrixCursor(new String[] {
+ ICON, ICON_PACKAGE, ICON_RESOURCE, TITLE,
+ _ID, CONTAINER, ITEM_TYPE, PROFILE_ID,
+ SCREEN, CELLX, CELLY,
+ });
+ mContext = InstrumentationRegistry.getTargetContext();
+
+ mMockApp = mock(LauncherAppState.class);
+ mMockIconCache = mock(IconCache.class);
+ when(mMockApp.getIconCache()).thenReturn(mMockIconCache);
+ when(mMockApp.getInvariantDeviceProfile()).thenReturn(mIDP);
+ when(mMockApp.getContext()).thenReturn(mContext);
+ mLauncherApps = LauncherAppsCompat.getInstance(mContext);
+
+ mLoaderCursor = new LoaderCursor(mCursor, mMockApp);
+ mLoaderCursor.allUsers.put(0, Process.myUserHandle());
+ }
+
+ private void initCursor(int itemType, String title) {
+ mCursor.newRow()
+ .add(_ID, 1)
+ .add(PROFILE_ID, 0)
+ .add(ITEM_TYPE, itemType)
+ .add(TITLE, title)
+ .add(CONTAINER, CONTAINER_DESKTOP);
+ }
+
+ @Test
+ public void getAppShortcutInfo_dontAllowMissing_invalidComponent() {
+ initCursor(ITEM_TYPE_APPLICATION, "");
+ assertTrue(mLoaderCursor.moveToNext());
+ ComponentName cn = new ComponentName(mContext.getPackageName(), "dummy-do");
+ assertNull(mLoaderCursor.getAppShortcutInfo(
+ new Intent().setComponent(cn), false /* allowMissingTarget */, true));
+ }
+
+ @Test
+ public void getAppShortcutInfo_dontAllowMissing_validComponent() {
+ initCursor(ITEM_TYPE_APPLICATION, "");
+ assertTrue(mLoaderCursor.moveToNext());
+
+ ComponentName cn = mLauncherApps.getActivityList(null, mLoaderCursor.user)
+ .get(0).getComponentName();
+ ShortcutInfo info = mLoaderCursor.getAppShortcutInfo(
+ new Intent().setComponent(cn), false /* allowMissingTarget */, true);
+ assertNotNull(info);
+ assertTrue(Utilities.isLauncherAppTarget(info.intent));
+ }
+
+ @Test
+ public void getAppShortcutInfo_allowMissing_invalidComponent() {
+ initCursor(ITEM_TYPE_APPLICATION, "");
+ assertTrue(mLoaderCursor.moveToNext());
+
+ ComponentName cn = new ComponentName(mContext.getPackageName(), "dummy-do");
+ ShortcutInfo info = mLoaderCursor.getAppShortcutInfo(
+ new Intent().setComponent(cn), true /* allowMissingTarget */, true);
+ assertNotNull(info);
+ assertTrue(Utilities.isLauncherAppTarget(info.intent));
+ }
+
+ @Test
+ public void loadSimpleShortcut() {
+ initCursor(ITEM_TYPE_SHORTCUT, "my-shortcut");
+ assertTrue(mLoaderCursor.moveToNext());
+
+ Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
+ when(mMockIconCache.getDefaultIcon(eq(mLoaderCursor.user))).thenReturn(icon);
+ ShortcutInfo info = mLoaderCursor.loadSimpleShortcut();
+ assertEquals(icon, info.iconBitmap);
+ assertEquals("my-shortcut", info.title);
+ assertEquals(ITEM_TYPE_SHORTCUT, info.itemType);
+ }
+
+ @Test
+ public void checkItemPlacement_wrongWorkspaceScreen() {
+ ArrayList<Long> workspaceScreens = new ArrayList<>(Arrays.asList(1L, 3L));
+ mIDP.numRows = 4;
+ mIDP.numColumns = 4;
+ mIDP.numHotseatIcons = 3;
+
+ // Item on unknown screen are not placed
+ assertFalse(mLoaderCursor.checkItemPlacement(
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 4L), workspaceScreens));
+ assertFalse(mLoaderCursor.checkItemPlacement(
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 5L), workspaceScreens));
+ assertFalse(mLoaderCursor.checkItemPlacement(
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2L), workspaceScreens));
+
+ assertTrue(mLoaderCursor.checkItemPlacement(
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens));
+ assertTrue(mLoaderCursor.checkItemPlacement(
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 3L), workspaceScreens));
+
+ }
+ @Test
+ public void checkItemPlacement_outsideBounds() {
+ ArrayList<Long> workspaceScreens = new ArrayList<>(Arrays.asList(1L, 2L));
+ mIDP.numRows = 4;
+ mIDP.numColumns = 4;
+ mIDP.numHotseatIcons = 3;
+
+ // Item outside screen bounds are not placed
+ assertFalse(mLoaderCursor.checkItemPlacement(
+ newItemInfo(4, 4, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens));
+ }
+
+ @Test
+ public void checkItemPlacement_overlappingItems() {
+ ArrayList<Long> workspaceScreens = new ArrayList<>(Arrays.asList(1L, 2L));
+ mIDP.numRows = 4;
+ mIDP.numColumns = 4;
+ mIDP.numHotseatIcons = 3;
+
+ // Overlapping items are not placed
+ assertTrue(mLoaderCursor.checkItemPlacement(
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens));
+ assertFalse(mLoaderCursor.checkItemPlacement(
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens));
+
+ assertTrue(mLoaderCursor.checkItemPlacement(
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2L), workspaceScreens));
+ assertFalse(mLoaderCursor.checkItemPlacement(
+ newItemInfo(0, 0, 1, 1, CONTAINER_DESKTOP, 2L), workspaceScreens));
+
+ assertTrue(mLoaderCursor.checkItemPlacement(
+ newItemInfo(1, 1, 1, 1, CONTAINER_DESKTOP, 1L), workspaceScreens));
+ assertTrue(mLoaderCursor.checkItemPlacement(
+ newItemInfo(2, 2, 2, 2, CONTAINER_DESKTOP, 1L), workspaceScreens));
+
+ assertFalse(mLoaderCursor.checkItemPlacement(
+ newItemInfo(3, 2, 1, 2, CONTAINER_DESKTOP, 1L), workspaceScreens));
+ }
+
+ @Test
+ public void checkItemPlacement_hotseat() {
+ ArrayList<Long> workspaceScreens = new ArrayList<>();
+ mIDP.numRows = 4;
+ mIDP.numColumns = 4;
+ mIDP.numHotseatIcons = 3;
+
+ // Hotseat items are only placed based on screenId
+ assertTrue(mLoaderCursor.checkItemPlacement(
+ newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 1L), workspaceScreens));
+ assertTrue(mLoaderCursor.checkItemPlacement(
+ newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 2L), workspaceScreens));
+
+ assertFalse(mLoaderCursor.checkItemPlacement(
+ newItemInfo(3, 3, 1, 1, CONTAINER_HOTSEAT, 3L), workspaceScreens));
+ }
+
+ private ItemInfo newItemInfo(int cellX, int cellY, int spanX, int spanY,
+ long container, long screenId) {
+ ItemInfo info = new ItemInfo();
+ info.cellX = cellX;
+ info.cellY = cellY;
+ info.spanX = spanX;
+ info.spanY = spanY;
+ info.container = container;
+ info.screenId = screenId;
+ return info;
+ }
+}
diff --git a/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java b/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java
index 4a80735..0ced7cf 100644
--- a/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java
+++ b/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java
@@ -1,12 +1,12 @@
package com.android.launcher3.ui;
+import android.content.pm.LauncherActivityInfo;
import android.os.Process;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
import android.test.suitebuilder.annotation.LargeTest;
-import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
@@ -17,7 +17,7 @@
@LargeTest
public class AllAppsAppLaunchTest extends LauncherInstrumentationTestCase {
- private LauncherActivityInfoCompat mSettingsApp;
+ private LauncherActivityInfo mSettingsApp;
@Override
protected void setUp() throws Exception {
diff --git a/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java b/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
index 8837b00..3f77bfd 100644
--- a/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
+++ b/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
@@ -1,12 +1,12 @@
package com.android.launcher3.ui;
+import android.content.pm.LauncherActivityInfo;
import android.os.Process;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
import android.test.suitebuilder.annotation.LargeTest;
-import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
@@ -17,7 +17,7 @@
@LargeTest
public class AllAppsIconToHomeTest extends LauncherInstrumentationTestCase {
- private LauncherActivityInfoCompat mSettingsApp;
+ private LauncherActivityInfo mSettingsApp;
@Override
protected void setUp() throws Exception {
diff --git a/tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java b/tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java
index fcf7122..42c6cd7 100644
--- a/tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java
+++ b/tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java
@@ -211,15 +211,22 @@
LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
LauncherSettings.Settings.call(mTargetContext.getContentResolver(),
LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG);
- ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mTargetContext);
+ resetLoaderState();
+ }
- runTestOnUiThread(new Runnable() {
- @Override
- public void run() {
- // Reset the loader state
- LauncherAppState.getInstance().getModel().resetLoadedState(true, true);
- }
- });
+ protected void resetLoaderState() {
+ try {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mTargetContext);
+ LauncherAppState.getInstance(mTargetContext).getModel()
+ .resetLoadedState(true, true);
+ }
+ });
+ } catch (Throwable t) {
+ throw new IllegalArgumentException(t);
+ }
}
/**
@@ -248,8 +255,7 @@
LauncherAppWidgetProviderInfo info = getOnUiThread(new Callable<LauncherAppWidgetProviderInfo>() {
@Override
public LauncherAppWidgetProviderInfo call() throws Exception {
- InvariantDeviceProfile idv =
- LauncherAppState.getInstance().getInvariantDeviceProfile();
+ InvariantDeviceProfile idv = LauncherAppState.getIDP(mTargetContext);
ComponentName searchComponent = ((SearchManager) mTargetContext
.getSystemService(Context.SEARCH_SERVICE)).getGlobalSearchActivity();
diff --git a/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java b/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
index 02d938c..c6828f0 100644
--- a/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
+++ b/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
@@ -1,5 +1,6 @@
package com.android.launcher3.ui;
+import android.content.pm.LauncherActivityInfo;
import android.graphics.Point;
import android.os.Process;
import android.support.test.uiautomator.By;
@@ -9,7 +10,6 @@
import android.view.MotionEvent;
import com.android.launcher3.R;
-import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
@@ -20,7 +20,7 @@
@LargeTest
public class ShortcutsLaunchTest extends LauncherInstrumentationTestCase {
- private LauncherActivityInfoCompat mSettingsApp;
+ private LauncherActivityInfo mSettingsApp;
@Override
protected void setUp() throws Exception {
diff --git a/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java b/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
index afe4832..d573eea 100644
--- a/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
+++ b/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
@@ -1,5 +1,6 @@
package com.android.launcher3.ui;
+import android.content.pm.LauncherActivityInfo;
import android.graphics.Point;
import android.os.Process;
import android.support.test.uiautomator.By;
@@ -9,7 +10,6 @@
import android.view.MotionEvent;
import com.android.launcher3.R;
-import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
@@ -20,7 +20,7 @@
@LargeTest
public class ShortcutsToHomeTest extends LauncherInstrumentationTestCase {
- private LauncherActivityInfoCompat mSettingsApp;
+ private LauncherActivityInfo mSettingsApp;
@Override
protected void setUp() throws Exception {