From 4f7eb4077e901a28b2b698060079292b56e991bd Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 10 Jul 2015 18:00:48 -0700 Subject: Fixing overview mode scale calculations. - Making the overview scale apply just like the spring loaded scale factor - Tweaking overview scale to make it not so small Change-Id: If93bac08609b0cfd9c9d9f8f6057498957378b56 --- res/values/config.xml | 4 ++-- src/com/android/launcher3/DeviceProfile.java | 19 +++++-------------- src/com/android/launcher3/Workspace.java | 21 ++++++++++++--------- .../WorkspaceStateTransitionAnimation.java | 3 ++- 4 files changed, 21 insertions(+), 26 deletions(-) diff --git a/res/values/config.xml b/res/values/config.xml index 73de79417..b2ba7a986 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -2,8 +2,6 @@ 20 - - 80 false @@ -30,6 +28,8 @@ 80 + + 70 diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index a50540d26..1c0743cbc 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -25,6 +25,7 @@ import android.graphics.Paint.FontMetrics; import android.graphics.Point; import android.graphics.Rect; import android.util.DisplayMetrics; +import android.util.Size; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; @@ -56,7 +57,6 @@ public class DeviceProfile { private final int overviewModeBarItemWidthPx; private final int overviewModeBarSpacerWidthPx; private final float overviewModeIconZoneRatio; - private final float overviewModeScaleFactor; // Workspace private int desiredWorkspaceLeftRightMarginPx; @@ -136,8 +136,6 @@ public class DeviceProfile { res.getDimensionPixelSize(R.dimen.dynamic_grid_overview_bar_spacer_width); overviewModeIconZoneRatio = res.getInteger(R.integer.config_dynamic_grid_overview_icon_zone_percentage) / 100f; - overviewModeScaleFactor = - res.getInteger(R.integer.config_dynamic_grid_overview_scale_percentage) / 100f; iconDrawablePaddingOriginalPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_icon_drawable_padding); @@ -338,18 +336,11 @@ public class DeviceProfile { } } - Rect getOverviewModeButtonBarRect() { + int getOverviewModeButtonBarHeight() { int zoneHeight = (int) (overviewModeIconZoneRatio * availableHeightPx); zoneHeight = Math.min(overviewModeMaxIconZoneHeightPx, Math.max(overviewModeMinIconZoneHeightPx, zoneHeight)); - return new Rect(0, availableHeightPx - zoneHeight, 0, availableHeightPx); - } - - public float getOverviewModeScale(boolean isLayoutRtl) { - Rect workspacePadding = getWorkspacePadding(isLayoutRtl); - Rect overviewBar = getOverviewModeButtonBarRect(); - int pageSpace = availableHeightPx - workspacePadding.top - workspacePadding.bottom; - return (overviewModeScaleFactor * (pageSpace - overviewBar.height())) / pageSpace; + return zoneHeight; } // The rect returned will be extended to below the system ui that covers the workspace @@ -480,7 +471,7 @@ public class DeviceProfile { // Layout the Overview Mode ViewGroup overviewMode = launcher.getOverviewPanel(); if (overviewMode != null) { - Rect r = getOverviewModeButtonBarRect(); + int overviewButtonBarHeight = getOverviewModeButtonBarHeight(); lp = (FrameLayout.LayoutParams) overviewMode.getLayoutParams(); lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; @@ -489,7 +480,7 @@ public class DeviceProfile { int maxWidth = totalItemWidth + (visibleChildCount-1) * overviewModeBarSpacerWidthPx; lp.width = Math.min(availableWidthPx, maxWidth); - lp.height = r.height(); + lp.height = overviewButtonBarHeight; overviewMode.setLayoutParams(lp); if (lp.width > totalItemWidth && visibleChildCount > 1) { diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 4a6b90afe..267787be8 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -306,8 +306,9 @@ public class Workspace extends PagedView TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Workspace, defStyle, 0); mSpringLoadedShrinkFactor = - res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f; - mOverviewModeShrinkFactor = grid.getOverviewModeScale(mIsRtl); + res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100.0f; + mOverviewModeShrinkFactor = + res.getInteger(R.integer.config_workspaceOverviewShrinkPercentage) / 100f; mOriginalDefaultPage = mDefaultPage = a.getInt(R.styleable.Workspace_defaultScreen, 1); a.recycle(); @@ -1952,15 +1953,17 @@ public class Workspace extends PagedView int getOverviewModeTranslationY() { DeviceProfile grid = mLauncher.getDeviceProfile(); - Rect overviewBar = grid.getOverviewModeButtonBarRect(); + Rect workspacePadding = grid.getWorkspacePadding(Utilities.isRtl(getResources())); + int overviewButtonBarHeight = grid.getOverviewModeButtonBarHeight(); - int availableHeight = getViewportHeight(); int scaledHeight = (int) (mOverviewModeShrinkFactor * getNormalChildHeight()); - int offsetFromTopEdge = (availableHeight - scaledHeight) / 2; - int offsetToCenterInOverview = (availableHeight - mInsets.top - overviewBar.height() - - scaledHeight) / 2; - - return -offsetFromTopEdge + mInsets.top + offsetToCenterInOverview; + int workspaceTop = mInsets.top + workspacePadding.top; + int workspaceBottom = getViewportHeight() - mInsets.bottom - workspacePadding.bottom; + int overviewTop = mInsets.top; + int overviewBottom = getViewportHeight() - mInsets.bottom - overviewButtonBarHeight; + int workspaceOffsetTopEdge = workspaceTop + ((workspaceBottom - workspaceTop) - scaledHeight) / 2; + int overviewOffsetTopEdge = overviewTop + (overviewBottom - overviewTop - scaledHeight) / 2; + return -workspaceOffsetTopEdge + overviewOffsetTopEdge; } /** diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index b8916a72b..e908ccd81 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -211,8 +211,9 @@ public class WorkspaceStateTransitionAnimation { mOverlayTransitionTime = res.getInteger(R.integer.config_overlayTransitionTime); mSpringLoadedShrinkFactor = res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100f; + mOverviewModeShrinkFactor = + res.getInteger(R.integer.config_workspaceOverviewShrinkPercentage) / 100f; mWorkspaceScrimAlpha = res.getInteger(R.integer.config_workspaceScrimAlpha) / 100f; - mOverviewModeShrinkFactor = grid.getOverviewModeScale(Utilities.isRtl(res)); mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens(); } -- cgit v1.2.3 From 53f9672b30b8a36bfae9f6492f732ccfb87723a4 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 13 Jul 2015 19:54:53 -0700 Subject: Fixing widget restore > Widget restore active flag was not cleared when the app was downloaded > Icon from session info was not getting cached Bug: 22413379 Change-Id: Ie096b929252200675a76dadd8c25cc3aa433671b --- src/com/android/launcher3/IconCache.java | 35 ++++++++++++++++++---------- src/com/android/launcher3/LauncherModel.java | 10 ++++++-- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java index 916418f18..193f458b5 100644 --- a/src/com/android/launcher3/IconCache.java +++ b/src/com/android/launcher3/IconCache.java @@ -540,7 +540,7 @@ public class IconCache { mCache.put(cacheKey, entry); // Check the DB first. - if (!getEntryFromDB(componentName, user, entry, useLowResIcon)) { + if (!getEntryFromDB(cacheKey, entry, useLowResIcon)) { if (info != null) { entry.icon = Utilities.createIconBitmap(info.getBadgedIcon(mIconDpi), mContext); } else { @@ -579,7 +579,14 @@ public class IconCache { Bitmap icon, CharSequence title) { removeFromMemCacheLocked(packageName, user); - CacheEntry entry = getEntryForPackageLocked(packageName, user, false); + ComponentKey cacheKey = getPackageKey(packageName, user); + CacheEntry entry = mCache.get(cacheKey); + + // For icon caching, do not go through DB. Just update the in-memory entry. + if (entry == null) { + entry = new CacheEntry(); + mCache.put(cacheKey, entry); + } if (!TextUtils.isEmpty(title)) { entry.title = title; } @@ -588,15 +595,18 @@ public class IconCache { } } + private static ComponentKey getPackageKey(String packageName, UserHandleCompat user) { + ComponentName cn = new ComponentName(packageName, packageName + EMPTY_CLASS_NAME); + return new ComponentKey(cn, user); + } + /** * Gets an entry for the package, which can be used as a fallback entry for various components. * This method is not thread safe, it must be called from a synchronized method. - * */ private CacheEntry getEntryForPackageLocked(String packageName, UserHandleCompat user, boolean useLowResIcon) { - ComponentName cn = new ComponentName(packageName, packageName + EMPTY_CLASS_NAME); - ComponentKey cacheKey = new ComponentKey(cn, user); + ComponentKey cacheKey = getPackageKey(packageName, user); CacheEntry entry = mCache.get(cacheKey); if (entry == null || (entry.isLowResIcon && !useLowResIcon)) { @@ -604,7 +614,7 @@ public class IconCache { boolean entryUpdated = true; // Check the DB first. - if (!getEntryFromDB(cn, user, entry, useLowResIcon)) { + if (!getEntryFromDB(cacheKey, entry, useLowResIcon)) { try { PackageInfo info = mPackageManager.getPackageInfo(packageName, 0); ApplicationInfo appInfo = info.applicationInfo; @@ -622,7 +632,8 @@ public class IconCache { // package updates. ContentValues values = newContentValues(entry.icon, entry.title.toString(), mPackageBgColor); - addIconToDB(values, cn, info, mUserManager.getSerialNumberForUser(user)); + addIconToDB(values, cacheKey.componentName, info, + mUserManager.getSerialNumberForUser(user)); } catch (NameNotFoundException e) { if (DEBUG) Log.d(TAG, "Application not installed " + packageName); @@ -667,14 +678,13 @@ public class IconCache { SQLiteDatabase.CONFLICT_REPLACE); } - private boolean getEntryFromDB(ComponentName component, UserHandleCompat user, - CacheEntry entry, boolean lowRes) { + private boolean getEntryFromDB(ComponentKey cacheKey, CacheEntry entry, boolean lowRes) { Cursor c = mIconDb.getReadableDatabase().query(IconDB.TABLE_NAME, new String[] {lowRes ? IconDB.COLUMN_ICON_LOW_RES : IconDB.COLUMN_ICON, IconDB.COLUMN_LABEL}, IconDB.COLUMN_COMPONENT + " = ? AND " + IconDB.COLUMN_USER + " = ?", - new String[] {component.flattenToString(), - Long.toString(mUserManager.getSerialNumberForUser(user))}, + new String[] {cacheKey.componentName.flattenToString(), + Long.toString(mUserManager.getSerialNumberForUser(cacheKey.user))}, null, null, null); try { if (c.moveToNext()) { @@ -685,7 +695,8 @@ public class IconCache { entry.title = ""; entry.contentDescription = ""; } else { - entry.contentDescription = mUserManager.getBadgedLabelForUser(entry.title, user); + entry.contentDescription = mUserManager.getBadgedLabelForUser( + entry.title, cacheKey.user); } return true; } diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index b60477fa0..0b67310fa 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -2163,7 +2163,11 @@ public class LauncherModel extends BroadcastReceiver appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, provider.provider); - int status = restoreStatus; + // The provider is available. So the widget is either + // available or not available. We do not need to track + // any future restore updates. + int status = restoreStatus & + ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED; if (!wasProviderReady) { // If provider was not previously ready, update the // status and UI flag. @@ -3155,7 +3159,9 @@ public class LauncherModel extends BroadcastReceiver if (mUser.equals(widgetInfo.user) && widgetInfo.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) && packageSet.contains(widgetInfo.providerName.getPackageName())) { - widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY; + widgetInfo.restoreStatus &= + ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY & + ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED; widgets.add(widgetInfo); updateItemInDatabase(context, widgetInfo); } -- cgit v1.2.3 From c115e647ad79face0b57240fe3a7e7be2ce85145 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 20 Jul 2015 14:23:43 -0700 Subject: Shifting hotseat icons to aling with all-apps icon, if the hotseat size is different from the source device Bug: 19074056 Change-Id: I8d8517971a3cde0dc38f653d151daeba90fa38a0 --- src/com/android/launcher3/LauncherBackupHelper.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java index 8c6fedbdc..8ac09d35d 100644 --- a/src/com/android/launcher3/LauncherBackupHelper.java +++ b/src/com/android/launcher3/LauncherBackupHelper.java @@ -153,6 +153,10 @@ public class LauncherBackupHelper implements BackupHelper { boolean restoreSuccessful; int restoredBackupVersion = 1; + // When migrating from a device which different hotseat configuration, the icons are shifted + // to center along the new all-apps icon. + private int mHotseatShift = 0; + public LauncherBackupHelper(Context context) { mContext = context; mExistingKeys = new HashSet(); @@ -285,10 +289,15 @@ public class LauncherBackupHelper implements BackupHelper { boolean isHotsetCompatible = false; if (currentProfile.allappsRank >= oldProfile.hotseatCount) { isHotsetCompatible = true; + mHotseatShift = 0; } - if ((currentProfile.hotseatCount >= oldProfile.hotseatCount) && - (currentProfile.allappsRank == oldProfile.allappsRank)) { + + if ((currentProfile.allappsRank >= oldProfile.allappsRank) + && ((currentProfile.hotseatCount - currentProfile.allappsRank) >= + (oldProfile.hotseatCount - oldProfile.allappsRank))) { + // There is enough space on both sides of the hotseat. isHotsetCompatible = true; + mHotseatShift = currentProfile.allappsRank - oldProfile.allappsRank; } return isHotsetCompatible && (currentProfile.desktopCols >= oldProfile.desktopCols) @@ -847,6 +856,11 @@ public class LauncherBackupHelper implements BackupHelper { throws IOException { Favorite favorite = unpackProto(new Favorite(), buffer, dataSize); + // If it is a hotseat item, move it accordingly. + if (favorite.container == Favorites.CONTAINER_HOTSEAT) { + favorite.screen += mHotseatShift; + } + ContentValues values = new ContentValues(); values.put(Favorites._ID, favorite.id); values.put(Favorites.SCREEN, favorite.screen); -- cgit v1.2.3 From df6ccf81960ab73d46570d56443e94c4df48e0c8 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 20 Jul 2015 14:32:48 -0700 Subject: Resizing the bitmap before caching it in the DB > The icon size in the backup can be different that what is required by the device. We should resize the icon, before caching it. Bug: 22413328 Change-Id: Id77c53edf8ea5e95a2d32dbe22be553120279ebd --- src/com/android/launcher3/IconCache.java | 6 ++++-- src/com/android/launcher3/LauncherBackupHelper.java | 9 +++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java index 916418f18..b4ca515d8 100644 --- a/src/com/android/launcher3/IconCache.java +++ b/src/com/android/launcher3/IconCache.java @@ -649,7 +649,7 @@ public class IconCache { * @param dpi the native density of the icon */ public void preloadIcon(ComponentName componentName, Bitmap icon, int dpi, String label, - long userSerial) { + long userSerial, InvariantDeviceProfile idp) { // TODO rescale to the correct native DPI try { PackageManager packageManager = mContext.getPackageManager(); @@ -660,7 +660,9 @@ public class IconCache { // pass } - ContentValues values = newContentValues(icon, label, Color.TRANSPARENT); + ContentValues values = newContentValues( + Bitmap.createScaledBitmap(icon, idp.iconBitmapSize, idp.iconBitmapSize, true), + label, Color.TRANSPARENT); values.put(IconDB.COLUMN_COMPONENT, componentName.flattenToString()); values.put(IconDB.COLUMN_USER, userSerial); mIconDb.getWritableDatabase().insertWithOnConflict(IconDB.TABLE_NAME, null, values, diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java index 8c6fedbdc..744f73bda 100644 --- a/src/com/android/launcher3/LauncherBackupHelper.java +++ b/src/com/android/launcher3/LauncherBackupHelper.java @@ -601,10 +601,11 @@ public class LauncherBackupHelper implements BackupHelper { Bitmap icon = BitmapFactory.decodeByteArray(res.data, 0, res.data.length); if (icon == null) { Log.w(TAG, "failed to unpack icon for " + key.name); + } else { + if (VERBOSE) Log.v(TAG, "saving restored icon as: " + key.name); + mIconCache.preloadIcon(ComponentName.unflattenFromString(key.name), icon, res.dpi, + "" /* label */, mUserSerial, mIdp); } - if (VERBOSE) Log.v(TAG, "saving restored icon as: " + key.name); - mIconCache.preloadIcon(ComponentName.unflattenFromString(key.name), icon, res.dpi, - "" /* label */, mUserSerial); } /** @@ -685,7 +686,7 @@ public class LauncherBackupHelper implements BackupHelper { Log.w(TAG, "failed to unpack widget icon for " + key.name); } else { mIconCache.preloadIcon(ComponentName.unflattenFromString(widget.provider), - icon, widget.icon.dpi, widget.label, mUserSerial); + icon, widget.icon.dpi, widget.label, mUserSerial, mIdp); } } -- cgit v1.2.3 From 86179020cc1a273d7e753d278fd844b90df456b0 Mon Sep 17 00:00:00 2001 From: bohu Date: Thu, 21 May 2015 08:20:38 -0700 Subject: Enable Launcher3 as default Home app The default Home app launcher2 is deprecated and cannot launch Nexus 6 or any other high resolution devices in emulator. This CL enables launcher3 as the default Home app, since it can handle Nexus 6 and is well maintained. Bug: 22609402 Change-Id: Iaba545fec218f79e40e0f72de5236ddadfabaa14 --- Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Android.mk b/Android.mk index 2e574783d..3ff542e61 100644 --- a/Android.mk +++ b/Android.mk @@ -36,7 +36,7 @@ LOCAL_AAPT_FLAGS := --auto-add-overlay LOCAL_SDK_VERSION := current LOCAL_PACKAGE_NAME := Launcher3 -LOCAL_OVERRIDES_PACKAGES := Launcher2 +LOCAL_OVERRIDES_PACKAGES := Home Launcher2 include $(BUILD_PACKAGE) -- cgit v1.2.3 From 107ea6345bff14ad172013783040bb127deacb61 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 20 Jul 2015 12:59:39 -0700 Subject: Adding rank column in backup > targetType was only added for M builds, so it can also be considered as v4 change. V3 which introduced minSpanX and minSpanY didn't contain targetType Bug: 22417713 Change-Id: I5c353674f7e0c2b5b4ab46e574fdb347d82028cd --- protos/backup.proto | 4 ++++ src/com/android/launcher3/LauncherBackupAgentHelper.java | 5 +++-- src/com/android/launcher3/LauncherBackupHelper.java | 15 ++++++++++++--- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/protos/backup.proto b/protos/backup.proto index d8d94e8cb..6704e08ad 100644 --- a/protos/backup.proto +++ b/protos/backup.proto @@ -101,7 +101,10 @@ message Favorite { optional string iconPackage = 16; optional string iconResource = 17; optional bytes icon = 18; + + // Added in backup version 4 optional TargetType targetType = 19 [default = TARGET_NONE]; + optional int32 rank = 20; } message Screen { @@ -121,6 +124,7 @@ message Widget { optional Resource icon = 4; optional Resource preview = 5; + // Added in backup version 3 // Assume that a widget is resizable upto 2x2 if no data is available optional int32 minSpanX = 6 [default = 2]; optional int32 minSpanY = 7 [default = 2]; diff --git a/src/com/android/launcher3/LauncherBackupAgentHelper.java b/src/com/android/launcher3/LauncherBackupAgentHelper.java index a92a889f9..b7860d45b 100644 --- a/src/com/android/launcher3/LauncherBackupAgentHelper.java +++ b/src/com/android/launcher3/LauncherBackupAgentHelper.java @@ -91,11 +91,12 @@ public class LauncherBackupAgentHelper extends BackupAgentHelper { LauncherAppState.getLauncherProvider().clearFlagEmptyDbCreated(); LauncherClings.synchonouslyMarkFirstRunClingDismissed(this); - // TODO: Update the backup set to include rank. + // Rank was added in v4. if (mHelper.restoredBackupVersion <= 3) { LauncherAppState.getLauncherProvider().updateFolderItemsRank(); - LauncherAppState.getLauncherProvider().convertShortcutsToLauncherActivities(); } + + LauncherAppState.getLauncherProvider().convertShortcutsToLauncherActivities(); } else { if (VERBOSE) Log.v(TAG, "Nothing was restored, clearing DB"); LauncherAppState.getLauncherProvider().createEmptyDB(); diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java index 38a4bdeb4..39603ad1b 100644 --- a/src/com/android/launcher3/LauncherBackupHelper.java +++ b/src/com/android/launcher3/LauncherBackupHelper.java @@ -75,7 +75,7 @@ public class LauncherBackupHelper implements BackupHelper { private static final boolean VERBOSE = LauncherBackupAgentHelper.VERBOSE; private static final boolean DEBUG = LauncherBackupAgentHelper.DEBUG; - private static final int BACKUP_VERSION = 3; + private static final int BACKUP_VERSION = 4; private static final int MAX_JOURNAL_SIZE = 1000000; // Journal key is such that it is always smaller than any dynamically generated @@ -107,6 +107,7 @@ public class LauncherBackupHelper implements BackupHelper { Favorites.SPANY, // 15 Favorites.TITLE, // 16 Favorites.PROFILE_ID, // 17 + Favorites.RANK, // 18 }; private static final int ID_INDEX = 0; @@ -126,6 +127,7 @@ public class LauncherBackupHelper implements BackupHelper { private static final int SPANX_INDEX = 14; private static final int SPANY_INDEX = 15; private static final int TITLE_INDEX = 16; + private static final int RANK_INDEX = 18; private static final String[] SCREEN_PROJECTION = { WorkspaceScreens._ID, // 0 @@ -441,7 +443,10 @@ public class LauncherBackupHelper implements BackupHelper { Key key = getKey(Key.FAVORITE, id); mKeys.add(key); final String backupKey = keyToBackupKey(key); - if (!mExistingKeys.contains(backupKey) || updateTime >= mLastBackupRestoreTime) { + + // Favorite proto changed in v4. Backup again if the version is old. + if (!mExistingKeys.contains(backupKey) || updateTime >= mLastBackupRestoreTime + || restoredBackupVersion < 4) { writeRowToBackup(key, packFavorite(cursor), data); } else { if (DEBUG) Log.d(TAG, "favorite already backup up: " + id); @@ -648,7 +653,9 @@ public class LauncherBackupHelper implements BackupHelper { } else { Log.w(TAG, "empty intent on appwidget: " + id); } - if (mExistingKeys.contains(backupKey) && restoredBackupVersion >= BACKUP_VERSION) { + + // Widget backup proto changed in v3. So add it again if the original backup is old. + if (mExistingKeys.contains(backupKey) && restoredBackupVersion >= 3) { if (DEBUG) Log.d(TAG, "already saved widget " + backupKey); // remember that we already backed this up previously @@ -783,6 +790,7 @@ public class LauncherBackupHelper implements BackupHelper { favorite.spanX = c.getInt(SPANX_INDEX); favorite.spanY = c.getInt(SPANY_INDEX); favorite.iconType = c.getInt(ICON_TYPE_INDEX); + favorite.rank = c.getInt(RANK_INDEX); String title = c.getString(TITLE_INDEX); if (!TextUtils.isEmpty(title)) { @@ -870,6 +878,7 @@ public class LauncherBackupHelper implements BackupHelper { values.put(Favorites.CELLY, favorite.cellY); values.put(Favorites.SPANX, favorite.spanX); values.put(Favorites.SPANY, favorite.spanY); + values.put(Favorites.RANK, favorite.rank); if (favorite.itemType == Favorites.ITEM_TYPE_SHORTCUT) { values.put(Favorites.ICON_TYPE, favorite.iconType); -- cgit v1.2.3 From ce77f36affd0ac37dc79fe261f34e13ddccde1cf Mon Sep 17 00:00:00 2001 From: Adam Cohen Date: Fri, 24 Jul 2015 15:56:33 -0700 Subject: Don't obfuscate Launcher3 Change-Id: I86ac745602c0d3c09842ed9553f7589c232f5d23 --- proguard.flags | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/proguard.flags b/proguard.flags index 6a9d6f345..a8e2b6092 100644 --- a/proguard.flags +++ b/proguard.flags @@ -1,3 +1,7 @@ +-keep,allowshrinking,allowoptimization class com.android.launcher3.** { + *; +} + -keep class com.android.launcher3.BaseRecyclerViewFastScrollBar { public void setWidth(int); public int getWidth(); @@ -63,4 +67,4 @@ -keep class com.android.launcher3.Workspace { public float getBackgroundAlpha(); public void setBackgroundAlpha(float); -} \ No newline at end of file +} -- cgit v1.2.3 From a9095e07ddd2318ceb81a2794219e07dd112df72 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Mon, 27 Jul 2015 13:35:33 -0700 Subject: Remove NPE inside WidgetsListAdapter during monkey actor test b/22518383 Change-Id: I1a683c49be93af150f7873390b723cee0d4ac5df --- src/com/android/launcher3/widget/WidgetsListAdapter.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java index d2ea25230..a54626a39 100644 --- a/src/com/android/launcher3/widget/WidgetsListAdapter.java +++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java @@ -87,6 +87,9 @@ public class WidgetsListAdapter extends Adapter { @Override public int getItemCount() { + if (mWidgetsModel == null) { + return 0; + } return mWidgetsModel.getPackageSize(); } -- cgit v1.2.3 From d30e845d89a069a8c1ee687791030e8e981170b3 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Mon, 27 Jul 2015 18:24:45 -0700 Subject: Overlay support lib RV resources in Android.mk Note: after this change, ag/735298 can be reverted. b/22719084 Change-Id: I83caf8832790b1df0a90a1339f6b24f481c51661 --- Android.mk | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Android.mk b/Android.mk index 3ff542e61..ec675c663 100644 --- a/Android.mk +++ b/Android.mk @@ -23,16 +23,25 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional +LOCAL_STATIC_JAVA_LIBRARIES := \ + android-support-v4 \ + android-support-v7-recyclerview + LOCAL_SRC_FILES := $(call all-java-files-under, src) \ $(call all-java-files-under, WallpaperPicker/src) \ $(call all-proto-files-under, protos) -LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/WallpaperPicker/res $(LOCAL_PATH)/res + +LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/WallpaperPicker/res \ + $(LOCAL_PATH)/res \ + $(LOCAL_PATH)/../../../prebuilts/sdk/current/support/v7/recyclerview/res + LOCAL_PROGUARD_FLAG_FILES := proguard.flags -LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 android-support-v7-recyclerview LOCAL_PROTOC_OPTIMIZE_TYPE := nano LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/ -LOCAL_AAPT_FLAGS := --auto-add-overlay +LOCAL_AAPT_FLAGS := \ + --auto-add-overlay \ + --extra-packages android.support.v7.recyclerview LOCAL_SDK_VERSION := current LOCAL_PACKAGE_NAME := Launcher3 -- cgit v1.2.3 From eea022530496bb5f53f9ae01fdef0cd9d0e8147d Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 27 Jul 2015 17:50:13 -0700 Subject: Fixing minor memory leak with name comparator. - WidgetsAndShortcutNameComparator was using the actual widget and shortcut resolve infos as the key to the label cache. Neither of these classes override hashCode() and we were retrieving a new set of widgets and shortcuts whenever packages changed so we would end up creating more and more entries in the cache. This isn't a huge leak, but could lead to problems if Launcher is used for long periods without being killed. - Now, we use a ComponentKey as the key, so that we don't keep a reference to the widget/shortcut infos and also ensures that they should hash to the same labels. Change-Id: I91347ee72363adbc2b075b67dba331e35ab1fe34 --- .../model/WidgetsAndShortcutNameComparator.java | 85 +++++++++++++++------- src/com/android/launcher3/model/WidgetsModel.java | 5 +- 2 files changed, 60 insertions(+), 30 deletions(-) diff --git a/src/com/android/launcher3/model/WidgetsAndShortcutNameComparator.java b/src/com/android/launcher3/model/WidgetsAndShortcutNameComparator.java index 61e895283..b99056023 100644 --- a/src/com/android/launcher3/model/WidgetsAndShortcutNameComparator.java +++ b/src/com/android/launcher3/model/WidgetsAndShortcutNameComparator.java @@ -1,13 +1,14 @@ package com.android.launcher3.model; +import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; - import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.Utilities; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.UserHandleCompat; +import com.android.launcher3.util.ComponentKey; import java.text.Collator; import java.util.Comparator; @@ -16,53 +17,81 @@ import java.util.HashMap; public class WidgetsAndShortcutNameComparator implements Comparator { private final AppWidgetManagerCompat mManager; private final PackageManager mPackageManager; - private final HashMap mLabelCache; + private final HashMap mLabelCache; private final Collator mCollator; private final UserHandleCompat mMainHandle; public WidgetsAndShortcutNameComparator(Context context) { mManager = AppWidgetManagerCompat.getInstance(context); mPackageManager = context.getPackageManager(); - mLabelCache = new HashMap(); + mLabelCache = new HashMap<>(); mCollator = Collator.getInstance(); mMainHandle = UserHandleCompat.myUserHandle(); } - @Override - public final int compare(Object a, Object b) { - String labelA, labelB; - if (mLabelCache.containsKey(a)) { - labelA = mLabelCache.get(a); - } else { - labelA = (a instanceof LauncherAppWidgetProviderInfo) - ? Utilities.trim(mManager.loadLabel((LauncherAppWidgetProviderInfo) a)) - : Utilities.trim(((ResolveInfo) a).loadLabel(mPackageManager)); - mLabelCache.put(a, labelA); - } - if (mLabelCache.containsKey(b)) { - labelB = mLabelCache.get(b); - } else { - labelB = (b instanceof LauncherAppWidgetProviderInfo) - ? Utilities.trim(mManager.loadLabel((LauncherAppWidgetProviderInfo) b)) - : Utilities.trim(((ResolveInfo) b).loadLabel(mPackageManager)); - mLabelCache.put(b, labelB); - } - - // Currently, there is no work profile shortcuts, hence only considering the widget cases. + /** + * Resets any stored state. + */ + public void reset() { + mLabelCache.clear(); + } - boolean aWorkProfile = (a instanceof LauncherAppWidgetProviderInfo) && - !mMainHandle.equals(mManager.getUser((LauncherAppWidgetProviderInfo) a)); - boolean bWorkProfile = (b instanceof LauncherAppWidgetProviderInfo) && - !mMainHandle.equals(mManager.getUser((LauncherAppWidgetProviderInfo) b)); + @Override + public final int compare(Object objA, Object objB) { + ComponentKey keyA = getComponentKey(objA); + ComponentKey keyB = getComponentKey(objB); // Independent of how the labels compare, if only one of the two widget info belongs to // work profile, put that one in the back. + boolean aWorkProfile = !mMainHandle.equals(keyA.user); + boolean bWorkProfile = !mMainHandle.equals(keyB.user); if (aWorkProfile && !bWorkProfile) { return 1; } if (!aWorkProfile && bWorkProfile) { return -1; } + + // Get the labels for comparison + String labelA = mLabelCache.get(keyA); + String labelB = mLabelCache.get(keyB); + if (labelA == null) { + labelA = getLabel(objA); + mLabelCache.put(keyA, labelA); + } + if (labelB == null) { + labelB = getLabel(objB); + mLabelCache.put(keyB, labelB); + } return mCollator.compare(labelA, labelB); } + + /** + * @return a component key for the given widget or shortcut info. + */ + private ComponentKey getComponentKey(Object o) { + if (o instanceof LauncherAppWidgetProviderInfo) { + LauncherAppWidgetProviderInfo widgetInfo = (LauncherAppWidgetProviderInfo) o; + return new ComponentKey(widgetInfo.provider, mManager.getUser(widgetInfo)); + } else { + ResolveInfo shortcutInfo = (ResolveInfo) o; + ComponentName cn = new ComponentName(shortcutInfo.activityInfo.packageName, + shortcutInfo.activityInfo.name); + // Currently, there are no work profile shortcuts + return new ComponentKey(cn, UserHandleCompat.myUserHandle()); + } + } + + /** + * @return the label for the given widget or shortcut info. This may be an expensive call. + */ + private String getLabel(Object o) { + if (o instanceof LauncherAppWidgetProviderInfo) { + LauncherAppWidgetProviderInfo widgetInfo = (LauncherAppWidgetProviderInfo) o; + return Utilities.trim(mManager.loadLabel(widgetInfo)); + } else { + ResolveInfo shortcutInfo = (ResolveInfo) o; + return Utilities.trim(shortcutInfo.loadLabel(mPackageManager)); + } + } }; diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java index 185dfcae3..cabff148f 100644 --- a/src/com/android/launcher3/model/WidgetsModel.java +++ b/src/com/android/launcher3/model/WidgetsModel.java @@ -39,7 +39,7 @@ public class WidgetsModel { private ArrayList mRawList; private final AppWidgetManagerCompat mAppWidgetMgr; - private final Comparator mWidgetAndShortcutNameComparator; + private final WidgetsAndShortcutNameComparator mWidgetAndShortcutNameComparator; private final Comparator mAppNameComparator; private final IconCache mIconCache; private final AppFilter mAppFilter; @@ -103,6 +103,7 @@ public class WidgetsModel { // clear the lists. mWidgetsList.clear(); mPackageItemInfos.clear(); + mWidgetAndShortcutNameComparator.reset(); // add and update. for (Object o: rawWidgetsShortcuts) { @@ -139,7 +140,7 @@ public class WidgetsModel { if (widgetsShortcutsList != null) { widgetsShortcutsList.add(o); } else { - widgetsShortcutsList = new ArrayList(); + widgetsShortcutsList = new ArrayList<>(); widgetsShortcutsList.add(o); pInfo = new PackageItemInfo(packageName); mIconCache.getTitleAndIconForApp(packageName, userHandle, -- cgit v1.2.3 From 70d5a07c5db9414742b0fd357d8ceb45c9f924ff Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Thu, 30 Jul 2015 12:03:28 -0700 Subject: Prevent crash when flattening ComponentKey to string with invalid user. Bug: 22658306 Change-Id: I213d44e0bb22ac0617d46c80ab8cfec8f750a2cc --- src/com/android/launcher3/util/ComponentKey.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/util/ComponentKey.java b/src/com/android/launcher3/util/ComponentKey.java index 6a7df4318..b7aafaea9 100644 --- a/src/com/android/launcher3/util/ComponentKey.java +++ b/src/com/android/launcher3/util/ComponentKey.java @@ -64,8 +64,11 @@ public class ComponentKey { * Encodes a component key as a string of the form [flattenedComponentString#userId]. */ public String flattenToString(Context context) { - return componentName.flattenToString() + "#" + - UserManagerCompat.getInstance(context).getSerialNumberForUser(user); + String flattened = componentName.flattenToString(); + if (user != null) { + flattened += "#" + UserManagerCompat.getInstance(context).getSerialNumberForUser(user); + } + return flattened; } @Override -- cgit v1.2.3 From deaf4d169b6e08ae2c41ae67ea97147164089b16 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Thu, 30 Jul 2015 12:53:33 -0700 Subject: Fixing issue with accessibility falsely reporting app count when there are no search results. Bug: 22672783 Change-Id: Ie40acc592e59699eac2a4ff2045a7f8ba029d33a --- .../launcher3/allapps/AllAppsGridAdapter.java | 37 +++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java index 057883cab..e96567c41 100644 --- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java +++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java @@ -22,12 +22,15 @@ import android.graphics.Paint; import android.graphics.PointF; import android.graphics.Rect; import android.os.Handler; +import android.support.v4.view.accessibility.AccessibilityRecordCompat; +import android.support.v4.view.accessibility.AccessibilityEventCompat; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; import android.widget.TextView; import com.android.launcher3.AppInfo; import com.android.launcher3.BubbleTextView; @@ -68,6 +71,38 @@ class AllAppsGridAdapter extends RecyclerView.Adapter Date: Thu, 30 Jul 2015 13:03:56 -0700 Subject: Remove references to FloatMath, deprecated in M -> Allows us to build against M SDK issue 22822360 Change-Id: I1178eb6bafc348699c5be8c29858eb3dff093e11 --- WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java | 7 +++---- WallpaperPicker/src/com/android/launcher3/CropView.java | 5 ++--- src/com/android/launcher3/LauncherScroller.java | 5 ++--- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java b/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java index a671ed2b9..38317eb41 100644 --- a/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java +++ b/WallpaperPicker/src/com/android/gallery3d/common/BitmapUtils.java @@ -23,7 +23,6 @@ import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.os.Build; -import android.util.FloatMath; import android.util.Log; import java.io.ByteArrayOutputStream; @@ -72,7 +71,7 @@ public class BitmapUtils { && minSideLength == UNCONSTRAINED) return 1; int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 : - (int) FloatMath.ceil(FloatMath.sqrt((float) (w * h) / maxNumOfPixels)); + (int) Math.ceil(Math.sqrt((float) (w * h) / maxNumOfPixels)); if (minSideLength == UNCONSTRAINED) { return lowerBound; @@ -96,7 +95,7 @@ public class BitmapUtils { // Find the min x that 1 / x >= scale public static int computeSampleSizeLarger(float scale) { - int initialSize = (int) FloatMath.floor(1f / scale); + int initialSize = (int) Math.floor(1f / scale); if (initialSize <= 1) return 1; return initialSize <= 8 @@ -107,7 +106,7 @@ public class BitmapUtils { // Find the max x that 1 / x <= scale. public static int computeSampleSize(float scale) { Utils.assertTrue(scale > 0); - int initialSize = Math.max(1, (int) FloatMath.ceil(1 / scale)); + int initialSize = Math.max(1, (int) Math.ceil(1 / scale)); return initialSize <= 8 ? Utils.nextPowerOf2(initialSize) : (initialSize + 7) / 8 * 8; diff --git a/WallpaperPicker/src/com/android/launcher3/CropView.java b/WallpaperPicker/src/com/android/launcher3/CropView.java index 578b8eafd..50f779add 100644 --- a/WallpaperPicker/src/com/android/launcher3/CropView.java +++ b/WallpaperPicker/src/com/android/launcher3/CropView.java @@ -21,7 +21,6 @@ import android.graphics.Matrix; import android.graphics.Point; import android.graphics.RectF; import android.util.AttributeSet; -import android.util.FloatMath; import android.view.MotionEvent; import android.view.ScaleGestureDetector; import android.view.ScaleGestureDetector.OnScaleGestureListener; @@ -300,12 +299,12 @@ public class CropView extends TiledImageView implements OnScaleGestureListener { adjustment[0] = (edges.right - getWidth()) / scale; } if (edges.top > 0) { - adjustment[1] = FloatMath.ceil(edges.top / scale); + adjustment[1] = (float) Math.ceil(edges.top / scale); } else if (edges.bottom < getHeight()) { adjustment[1] = (edges.bottom - getHeight()) / scale; } for (int dim = 0; dim <= 1; dim++) { - if (coef[dim] > 0) adjustment[dim] = FloatMath.ceil(adjustment[dim]); + if (coef[dim] > 0) adjustment[dim] = (float) Math.ceil(adjustment[dim]); } mInverseRotateMatrix.mapPoints(adjustment); diff --git a/src/com/android/launcher3/LauncherScroller.java b/src/com/android/launcher3/LauncherScroller.java index 3bd0a78c4..bbc7e4cab 100644 --- a/src/com/android/launcher3/LauncherScroller.java +++ b/src/com/android/launcher3/LauncherScroller.java @@ -20,7 +20,6 @@ import android.animation.TimeInterpolator; import android.content.Context; import android.hardware.SensorManager; import android.os.Build; -import android.util.FloatMath; import android.view.ViewConfiguration; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; @@ -409,7 +408,7 @@ public class LauncherScroller { float dx = (float) (mFinalX - mStartX); float dy = (float) (mFinalY - mStartY); - float hyp = FloatMath.sqrt(dx * dx + dy * dy); + float hyp = (float) Math.sqrt(dx * dx + dy * dy); float ndx = dx / hyp; float ndy = dy / hyp; @@ -426,7 +425,7 @@ public class LauncherScroller { mMode = FLING_MODE; mFinished = false; - float velocity = FloatMath.sqrt(velocityX * velocityX + velocityY * velocityY); + float velocity = (float) Math.sqrt(velocityX * velocityX + velocityY * velocityY); mVelocity = velocity; mDuration = getSplineFlingDuration(velocity); -- cgit v1.2.3 From b9f932e08902c21020b6a98372c1a68548b8de59 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Thu, 30 Jul 2015 15:04:59 -0700 Subject: Prevent from widget cell preview image from being cut off. b/22541466 >TL;DR;; when introducing mProfileBadgeMargin to correctly place > work profile badge. Drawing origin of the preview image resulted > to the left of (0, 0). Change-Id: Ic52fc2e17c55c76f4f57aa833451ffa19bbbeb09 --- src/com/android/launcher3/WidgetPreviewLoader.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java index 629387ed0..2a8053d52 100644 --- a/src/com/android/launcher3/WidgetPreviewLoader.java +++ b/src/com/android/launcher3/WidgetPreviewLoader.java @@ -386,7 +386,7 @@ public class WidgetPreviewLoader { preScaledWidthOut[0] = previewWidth; } if (previewWidth > maxPreviewWidth) { - scale = maxPreviewWidth / (float) previewWidth; + scale = (maxPreviewWidth - 2 * mProfileBadgeMargin) / (float) (previewWidth); } if (scale != 1f) { previewWidth = (int) (scale * previewWidth); @@ -405,7 +405,7 @@ public class WidgetPreviewLoader { } // Draw the scaled preview into the final bitmap - int x = (preview.getWidth() - previewWidth - mProfileBadgeMargin) / 2; + int x = (preview.getWidth() - previewWidth) / 2; if (widgetPreviewExists) { drawable.setBounds(x, 0, x + previewWidth, previewHeight); drawable.draw(c); -- cgit v1.2.3 From cb7674118c6fa6849e657fb8fea25c8fd93477cc Mon Sep 17 00:00:00 2001 From: Adam Cohen Date: Fri, 31 Jul 2015 10:58:44 -0700 Subject: Add proto flag "javanano_use_deprecated_package" to avoid build breakage Change-Id: Iea8a7bc2bb385e066b3f972105224fee3eb7c894 --- protos/backup.proto | 1 + 1 file changed, 1 insertion(+) diff --git a/protos/backup.proto b/protos/backup.proto index f3ad0b61f..e1af696d4 100644 --- a/protos/backup.proto +++ b/protos/backup.proto @@ -18,6 +18,7 @@ syntax = "proto2"; package launcher_backup; +option javanano_use_deprecated_package = true; option java_package = "com.android.launcher3.backup"; option java_outer_classname = "BackupProtos"; -- cgit v1.2.3 From e5bb705fb79f18df8680958dcf2c5460e16c90b6 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 27 Jul 2015 14:36:07 -0700 Subject: Homescreen migration from a larger grid to a smaller grid. Adding support for restoring from a larger device, if the grid size difference is not more that 1. During restore add all the items in the DB, and run a one-time migration the next time launcher starts. The migration strategy is defined in ShrinkWorkspaceTask.java which involves resizing, moving and removing some items. Change-Id: I6ee411f6db5bf0152b527e16146a88c56dec2d97 --- src/com/android/launcher3/LauncherAppState.java | 3 +- .../launcher3/LauncherAppWidgetProviderInfo.java | 12 + .../launcher3/LauncherBackupAgentHelper.java | 9 + .../android/launcher3/LauncherBackupHelper.java | 54 +- src/com/android/launcher3/LauncherModel.java | 22 +- src/com/android/launcher3/LauncherProvider.java | 2 +- src/com/android/launcher3/LauncherSettings.java | 2 +- .../launcher3/model/MigrateFromRestoreTask.java | 765 +++++++++++++++++++++ 8 files changed, 848 insertions(+), 21 deletions(-) create mode 100644 src/com/android/launcher3/model/MigrateFromRestoreTask.java diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 0b7b1fdc4..ecaf8016e 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -17,7 +17,6 @@ package com.android.launcher3; import android.app.SearchManager; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -147,7 +146,7 @@ public class LauncherAppState { sLauncherProvider = new WeakReference(provider); } - static LauncherProvider getLauncherProvider() { + public static LauncherProvider getLauncherProvider() { return sLauncherProvider.get(); } diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java index 85af92f30..9ba78530d 100644 --- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java +++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java @@ -5,6 +5,7 @@ import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; +import android.graphics.Point; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Parcel; @@ -110,4 +111,15 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo { mMinSpanY = minResizeSpan[1]; } } + + public Point getMinSpans(InvariantDeviceProfile idp, Context context) { + // Calculate the spans corresponding to any one of the orientations as it should not change + // based on orientation. + // TODO: Use the max of both profiles + int[] minSpans = CellLayout.rectToCell( + idp.portraitProfile, context, minResizeWidth, minResizeHeight, null); + return new Point( + (resizeMode & RESIZE_HORIZONTAL) != 0 ? minSpans[0] : -1, + (resizeMode & RESIZE_VERTICAL) != 0 ? minSpans[1] : -1); + } } diff --git a/src/com/android/launcher3/LauncherBackupAgentHelper.java b/src/com/android/launcher3/LauncherBackupAgentHelper.java index b7860d45b..611ab2e92 100644 --- a/src/com/android/launcher3/LauncherBackupAgentHelper.java +++ b/src/com/android/launcher3/LauncherBackupAgentHelper.java @@ -24,6 +24,8 @@ import android.database.Cursor; import android.os.ParcelFileDescriptor; import android.util.Log; +import com.android.launcher3.model.MigrateFromRestoreTask; + import java.io.IOException; public class LauncherBackupAgentHelper extends BackupAgentHelper { @@ -96,6 +98,13 @@ public class LauncherBackupAgentHelper extends BackupAgentHelper { LauncherAppState.getLauncherProvider().updateFolderItemsRank(); } + if (mHelper.shouldAttemptWorkspaceMigration()) { + MigrateFromRestoreTask.markForMigration(getApplicationContext(), + (int) mHelper.migrationCompatibleProfileData.desktopCols, + (int) mHelper.migrationCompatibleProfileData.desktopRows, + mHelper.widgetSizes); + } + LauncherAppState.getLauncherProvider().convertShortcutsToLauncherActivities(); } else { if (VERBOSE) Log.v(TAG, "Nothing was restored, clearing DB"); diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java index 39603ad1b..136556b92 100644 --- a/src/com/android/launcher3/LauncherBackupHelper.java +++ b/src/com/android/launcher3/LauncherBackupHelper.java @@ -32,6 +32,7 @@ import android.content.res.XmlResourceParser; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Point; import android.graphics.drawable.Drawable; import android.os.ParcelFileDescriptor; import android.text.TextUtils; @@ -152,6 +153,9 @@ public class LauncherBackupHelper implements BackupHelper { private DeviceProfieData mDeviceProfileData; private InvariantDeviceProfile mIdp; + DeviceProfieData migrationCompatibleProfileData; + HashSet widgetSizes = new HashSet<>(); + boolean restoreSuccessful; int restoredBackupVersion = 1; @@ -288,9 +292,9 @@ public class LauncherBackupHelper implements BackupHelper { return true; } - boolean isHotsetCompatible = false; + boolean isHotseatCompatible = false; if (currentProfile.allappsRank >= oldProfile.hotseatCount) { - isHotsetCompatible = true; + isHotseatCompatible = true; mHotseatShift = 0; } @@ -298,12 +302,28 @@ public class LauncherBackupHelper implements BackupHelper { && ((currentProfile.hotseatCount - currentProfile.allappsRank) >= (oldProfile.hotseatCount - oldProfile.allappsRank))) { // There is enough space on both sides of the hotseat. - isHotsetCompatible = true; + isHotseatCompatible = true; mHotseatShift = currentProfile.allappsRank - oldProfile.allappsRank; } - return isHotsetCompatible && (currentProfile.desktopCols >= oldProfile.desktopCols) - && (currentProfile.desktopRows >= oldProfile.desktopRows); + if (!isHotseatCompatible) { + return false; + } + if ((currentProfile.desktopCols >= oldProfile.desktopCols) + && (currentProfile.desktopRows >= oldProfile.desktopRows)) { + return true; + } + + if ((oldProfile.desktopCols - currentProfile.desktopCols <= 1) && + (oldProfile.desktopRows - currentProfile.desktopRows <= 1)) { + // Allow desktop migration when row and/or column count contracts by 1. + + migrationCompatibleProfileData = initDeviceProfileData(mIdp); + migrationCompatibleProfileData.desktopCols = oldProfile.desktopCols; + migrationCompatibleProfileData.desktopRows = oldProfile.desktopRows; + return true; + } + return false; } /** @@ -706,7 +726,8 @@ public class LauncherBackupHelper implements BackupHelper { } } - // future site of widget table mutation + // Cache widget min sizes incase migration is required. + widgetSizes.add(widget.provider + "#" + widget.minSpanX + "," + widget.minSpanY); } /** create a new key, with an integer ID. @@ -904,7 +925,11 @@ public class LauncherBackupHelper implements BackupHelper { UserManagerCompat.getInstance(mContext).getSerialNumberForUser(myUserHandle); values.put(LauncherSettings.Favorites.PROFILE_ID, userSerialNumber); - DeviceProfieData currentProfile = mDeviceProfileData; + // If we will attempt grid resize, use the original profile to validate grid size, as + // anything which fits in the original grid should fit in the current grid after + // grid migration. + DeviceProfieData currentProfile = migrationCompatibleProfileData == null + ? mDeviceProfileData : migrationCompatibleProfileData; if (favorite.itemType == Favorites.ITEM_TYPE_APPWIDGET) { if (!TextUtils.isEmpty(favorite.appWidgetProvider)) { @@ -996,14 +1021,9 @@ public class LauncherBackupHelper implements BackupHelper { widget.icon.dpi = dpi; } - // Calculate the spans corresponding to any one of the orientations as it should not change - // based on orientation. - int[] minSpans = CellLayout.rectToCell( - mIdp.portraitProfile, mContext, info.minResizeWidth, info.minResizeHeight, null); - widget.minSpanX = (info.resizeMode & LauncherAppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0 - ? minSpans[0] : -1; - widget.minSpanY = (info.resizeMode & LauncherAppWidgetProviderInfo.RESIZE_VERTICAL) != 0 - ? minSpans[1] : -1; + Point spans = info.getMinSpans(mIdp, mContext); + widget.minSpanX = spans.x; + widget.minSpanY = spans.y; return widget; } @@ -1188,6 +1208,10 @@ public class LauncherBackupHelper implements BackupHelper { } } + public boolean shouldAttemptWorkspaceMigration() { + return migrationCompatibleProfileData != null; + } + /** * A class to check if an activity can handle one of the intents from a list of * predefined intents. diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 0b67310fa..7e75f9793 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -27,6 +27,7 @@ import android.content.Context; import android.content.Intent; import android.content.Intent.ShortcutIconResource; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; @@ -55,6 +56,7 @@ import com.android.launcher3.compat.PackageInstallerCompat; import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.compat.UserManagerCompat; +import com.android.launcher3.model.MigrateFromRestoreTask; import com.android.launcher3.model.WidgetsModel; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.CursorIconInfo; @@ -1133,7 +1135,7 @@ public class LauncherModel extends BroadcastReceiver * Update the order of the workspace screens in the database. The array list contains * a list of screen ids in the order that they should appear. */ - void updateWorkspaceScreenOrder(Context context, final ArrayList screens) { + public void updateWorkspaceScreenOrder(Context context, final ArrayList screens) { final ArrayList screensCopy = new ArrayList(screens); final ContentResolver cr = context.getContentResolver(); final Uri uri = LauncherSettings.WorkspaceScreens.CONTENT_URI; @@ -1411,7 +1413,7 @@ public class LauncherModel extends BroadcastReceiver /** * Loads the workspace screen ids in an ordered list. */ - @Thunk static ArrayList loadWorkspaceScreensDb(Context context) { + public static ArrayList loadWorkspaceScreensDb(Context context) { final ContentResolver contentResolver = context.getContentResolver(); final Uri screensUri = LauncherSettings.WorkspaceScreens.CONTENT_URI; @@ -1757,6 +1759,22 @@ public class LauncherModel extends BroadcastReceiver int countX = (int) profile.numColumns; int countY = (int) profile.numRows; + + if (MigrateFromRestoreTask.shouldRunTask(mContext)) { + try { + MigrateFromRestoreTask task = new MigrateFromRestoreTask(mContext); + // Clear the flags before starting the task, so that we do not run the task + // again, in case there was an uncaught error. + MigrateFromRestoreTask.clearFlags(mContext); + task.execute(); + } catch (Exception e) { + Log.e(TAG, "Error during grid migration", e); + + // Clear workspace. + mFlags = mFlags | LOADER_FLAG_CLEAR_WORKSPACE; + } + } + if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) { Launcher.addDumpLog(TAG, "loadWorkspace: resetting launcher database", true); LauncherAppState.getLauncherProvider().deleteDatabase(); diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index cc5e18bc1..6cbb267be 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -71,7 +71,7 @@ public class LauncherProvider extends ContentProvider { private static final int DATABASE_VERSION = 26; static final String OLD_AUTHORITY = "com.android.launcher2.settings"; - static final String AUTHORITY = ProviderConfig.AUTHORITY; + public static final String AUTHORITY = ProviderConfig.AUTHORITY; static final String TABLE_FAVORITES = LauncherSettings.Favorites.TABLE_NAME; static final String TABLE_WORKSPACE_SCREENS = LauncherSettings.WorkspaceScreens.TABLE_NAME; diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java index f2c85a195..8a5804f34 100644 --- a/src/com/android/launcher3/LauncherSettings.java +++ b/src/com/android/launcher3/LauncherSettings.java @@ -143,7 +143,7 @@ public class LauncherSettings { * * @return The unique content URL for the specified row. */ - static Uri getContentUri(long id) { + public static Uri getContentUri(long id) { return Uri.parse("content://" + ProviderConfig.AUTHORITY + "/" + TABLE_NAME + "/" + id); } diff --git a/src/com/android/launcher3/model/MigrateFromRestoreTask.java b/src/com/android/launcher3/model/MigrateFromRestoreTask.java new file mode 100644 index 000000000..cb90c8bc9 --- /dev/null +++ b/src/com/android/launcher3/model/MigrateFromRestoreTask.java @@ -0,0 +1,765 @@ +package com.android.launcher3.model; + +import android.content.ComponentName; +import android.content.ContentProviderOperation; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.database.Cursor; +import android.graphics.Point; +import android.text.TextUtils; +import android.util.Log; + +import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherAppWidgetProviderInfo; +import com.android.launcher3.LauncherModel; +import com.android.launcher3.LauncherProvider; +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.Utilities; +import com.android.launcher3.compat.PackageInstallerCompat; +import com.android.launcher3.compat.UserHandleCompat; +import com.android.launcher3.util.LongArrayMap; +import com.android.launcher3.util.Thunk; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; + +/** + * This class takes care of shrinking the workspace (by maximum of one row and one column), as a + * result of restoring from a larger device. + */ +public class MigrateFromRestoreTask { + + private static final String TAG = "MigrateFromRestoreTask"; + private static final boolean DEBUG = false; + + private static final String KEY_MIGRATION_SOURCE_SIZE = "migration_restore_src_size"; + private static final String KEY_MIGRATION_WIDGET_MINSIZE = "migration_widget_min_size"; + + // These are carefully selected weights for various item types (Math.random?), to allow for + // the lease absurd migration experience. + private static final float WT_SHORTCUT = 1; + private static final float WT_APPLICATION = 0.8f; + private static final float WT_WIDGET_MIN = 2; + private static final float WT_WIDGET_FACTOR = 0.6f; + private static final float WT_FOLDER_FACTOR = 0.5f; + + private final Context mContext; + private final ContentValues mTempValues = new ContentValues(); + private final HashMap mWidgetMinSize; + private final InvariantDeviceProfile mIdp; + + private HashSet mValidPackages; + public ArrayList mEntryToRemove; + private ArrayList mUpdateOperations; + + private ArrayList mCarryOver; + + private final int mSrcX, mSrcY; + @Thunk final int mTrgX, mTrgY; + private final boolean mShouldRemoveX, mShouldRemoveY; + + public MigrateFromRestoreTask(Context context) { + mContext = context; + + SharedPreferences prefs = prefs(context); + Point sourceSize = parsePoint(prefs.getString(KEY_MIGRATION_SOURCE_SIZE, "")); + mSrcX = sourceSize.x; + mSrcY = sourceSize.y; + + mWidgetMinSize = new HashMap(); + for (String s : prefs.getStringSet(KEY_MIGRATION_WIDGET_MINSIZE, + Collections.emptySet())) { + String[] parts = s.split("#"); + mWidgetMinSize.put(parts[0], parsePoint(parts[1])); + } + + mIdp = LauncherAppState.getInstance().getInvariantDeviceProfile(); + mTrgX = mIdp.numColumns; + mTrgY = mIdp.numRows; + mShouldRemoveX = mTrgX < mSrcX; + mShouldRemoveY = mTrgY < mSrcY; + } + + public void execute() throws Exception { + mEntryToRemove = new ArrayList<>(); + mCarryOver = new ArrayList<>(); + mUpdateOperations = new ArrayList<>(); + + // Initialize list of valid packages. This contain all the packages which are already on + // the device and packages which are being installed. Any item which doesn't belong to + // this set is removed. + // Since the loader removes such items anyway, removing these items here doesn't cause any + // extra data loss and gives us more free space on the grid for better migration. + mValidPackages = new HashSet<>(); + for (PackageInfo info : mContext.getPackageManager().getInstalledPackages(0)) { + mValidPackages.add(info.packageName); + } + mValidPackages.addAll(PackageInstallerCompat.getInstance(mContext) + .updateAndGetActiveSessionCache().keySet()); + + ArrayList allScreens = LauncherModel.loadWorkspaceScreensDb(mContext); + if (allScreens.isEmpty()) { + throw new Exception("Unable to get workspace screens"); + } + + for (long screenId : allScreens) { + if (DEBUG) { + Log.d(TAG, "Migrating " + screenId); + } + migrateScreen(screenId); + } + + if (!mCarryOver.isEmpty()) { + LongArrayMap itemMap = new LongArrayMap<>(); + for (DbEntry e : mCarryOver) { + itemMap.put(e.id, e); + } + + do { + // Some items are still remaining. Try adding a few new screens. + + // At every iteration, make sure that at least one item is removed from + // {@link #mCarryOver}, to prevent an infinite loop. If no item could be removed, + // break the loop and abort migration by throwing an exception. + OptimalPlacementSolution placement = new OptimalPlacementSolution( + new boolean[mTrgX][mTrgY], deepCopy(mCarryOver), true); + placement.find(); + if (placement.finalPlacedItems.size() > 0) { + long newScreenId = LauncherAppState.getLauncherProvider().generateNewScreenId(); + allScreens.add(newScreenId); + for (DbEntry item : placement.finalPlacedItems) { + if (!mCarryOver.remove(itemMap.get(item.id))) { + throw new Exception("Unable to find matching items"); + } + item.screenId = newScreenId; + update(item); + } + } else { + throw new Exception("None of the items can be placed on an empty screen"); + } + + } while (!mCarryOver.isEmpty()); + + + LauncherAppState.getInstance().getModel() + .updateWorkspaceScreenOrder(mContext, allScreens); + } + + // Update items + mContext.getContentResolver().applyBatch(LauncherProvider.AUTHORITY, mUpdateOperations); + + if (!mEntryToRemove.isEmpty()) { + if (DEBUG) { + Log.d(TAG, "Removing items: " + TextUtils.join(", ", mEntryToRemove)); + } + mContext.getContentResolver().delete(LauncherSettings.Favorites.CONTENT_URI, + Utilities.createDbSelectionQuery( + LauncherSettings.Favorites._ID, mEntryToRemove), null); + } + + // Make sure we haven't removed everything. + final Cursor c = mContext.getContentResolver().query( + LauncherSettings.Favorites.CONTENT_URI, null, null, null, null); + boolean hasData = c.moveToNext(); + c.close(); + if (!hasData) { + throw new Exception("Removed every thing during grid resize"); + } + } + + /** + * Migrate a particular screen id. + * Strategy: + * 1) For all possible combinations of row and column, pick the one which causes the least + * data loss: {@link #tryRemove(int, int, ArrayList, float[])} + * 2) Maintain a list of all lost items before this screen, and add any new item lost from + * this screen to that list as well. + * 3) If all those items from the above list can be placed on this screen, place them + * (otherwise they are placed on a new screen). + */ + private void migrateScreen(long screenId) { + ArrayList items = loadEntries(screenId); + + int removedCol = Integer.MAX_VALUE; + int removedRow = Integer.MAX_VALUE; + + // removeWt represents the cost function for loss of items during migration, and moveWt + // represents the cost function for repositioning the items. moveWt is only considered if + // removeWt is same for two different configurations. + // Start with Float.MAX_VALUE (assuming full data) and pick the configuration with least + // cost. + float removeWt = Float.MAX_VALUE; + float moveWt = Float.MAX_VALUE; + float[] outLoss = new float[2]; + ArrayList finalItems = null; + + // Try removing all possible combinations + for (int x = 0; x < mSrcX; x++) { + for (int y = 0; y < mSrcY; y++) { + // Use a deep copy when trying out a particular combination as it can change + // the underlying object. + ArrayList itemsOnScreen = tryRemove(x, y, deepCopy(items), outLoss); + + if ((outLoss[0] < removeWt) || ((outLoss[0] == removeWt) && (outLoss[1] < moveWt))) { + removeWt = outLoss[0]; + moveWt = outLoss[1]; + removedCol = mShouldRemoveX ? x : removedCol; + removedRow = mShouldRemoveY ? y : removedRow; + finalItems = itemsOnScreen; + } + + // No need to loop over all rows, if a row removal is not needed. + if (!mShouldRemoveY) { + break; + } + } + + if (!mShouldRemoveX) { + break; + } + } + + if (DEBUG) { + Log.d(TAG, String.format("Removing row %d, column %d on screen %d", + removedRow, removedCol, screenId)); + } + + LongArrayMap itemMap = new LongArrayMap<>(); + for (DbEntry e : deepCopy(items)) { + itemMap.put(e.id, e); + } + + for (DbEntry item : finalItems) { + DbEntry org = itemMap.get(item.id); + itemMap.remove(item.id); + + // Check if update is required + if (!item.columnsSame(org)) { + update(item); + } + } + + // The remaining items in {@link #itemMap} are those which didn't get placed. + for (DbEntry item : itemMap) { + mCarryOver.add(item); + } + + if (!mCarryOver.isEmpty() && removeWt == 0) { + // No new items were removed in this step. Try placing all the items on this screen. + boolean[][] occupied = new boolean[mTrgX][mTrgY]; + for (DbEntry item : finalItems) { + markCells(occupied, item, true); + } + + OptimalPlacementSolution placement = new OptimalPlacementSolution(occupied, + deepCopy(mCarryOver), true); + placement.find(); + if (placement.lowestWeightLoss == 0) { + // All items got placed + + for (DbEntry item : placement.finalPlacedItems) { + item.screenId = screenId; + update(item); + } + + mCarryOver.clear(); + } + } + } + + /** + * Updates an item in the DB. + */ + private void update(DbEntry item) { + mTempValues.clear(); + item.addToContentValues(mTempValues); + mUpdateOperations.add(ContentProviderOperation + .newUpdate(LauncherSettings.Favorites.getContentUri(item.id)) + .withValues(mTempValues).build()); + } + + /** + * Tries the remove the provided row and column. + * @param items all the items on the screen under operation + * @param outLoss array of size 2. The first entry is filled with weight loss, and the second + * with the overall item movement. + */ + private ArrayList tryRemove(int col, int row, ArrayList items, + float[] outLoss) { + boolean[][] occupied = new boolean[mTrgX][mTrgY]; + + col = mShouldRemoveX ? col : Integer.MAX_VALUE; + row = mShouldRemoveY ? row : Integer.MAX_VALUE; + + ArrayList finalItems = new ArrayList<>(); + ArrayList removedItems = new ArrayList<>(); + + for (DbEntry item : items) { + if ((item.cellX <= col && (item.spanX + item.cellX) > col) + || (item.cellY <= row && (item.spanY + item.cellY) > row)) { + removedItems.add(item); + if (item.cellX >= col) item.cellX --; + if (item.cellY >= row) item.cellY --; + } else { + if (item.cellX > col) item.cellX --; + if (item.cellY > row) item.cellY --; + finalItems.add(item); + markCells(occupied, item, true); + } + } + + OptimalPlacementSolution placement = new OptimalPlacementSolution(occupied, removedItems); + placement.find(); + finalItems.addAll(placement.finalPlacedItems); + outLoss[0] = placement.lowestWeightLoss; + outLoss[1] = placement.lowestMoveCost; + return finalItems; + } + + @Thunk void markCells(boolean[][] occupied, DbEntry item, boolean val) { + for (int i = item.cellX; i < (item.cellX + item.spanX); i++) { + for (int j = item.cellY; j < (item.cellY + item.spanY); j++) { + occupied[i][j] = val; + } + } + } + + @Thunk boolean isVacant(boolean[][] occupied, int x, int y, int w, int h) { + if (x + w > mTrgX) return false; + if (y + h > mTrgY) return false; + + for (int i = 0; i < w; i++) { + for (int j = 0; j < h; j++) { + if (occupied[i + x][j + y]) { + return false; + } + } + } + return true; + } + + private class OptimalPlacementSolution { + private final ArrayList itemsToPlace; + private final boolean[][] occupied; + + // If set to true, item movement are not considered in move cost, leading to a more + // linear placement. + private final boolean ignoreMove; + + float lowestWeightLoss = Float.MAX_VALUE; + float lowestMoveCost = Float.MAX_VALUE; + ArrayList finalPlacedItems; + + public OptimalPlacementSolution(boolean[][] occupied, ArrayList itemsToPlace) { + this(occupied, itemsToPlace, false); + } + + public OptimalPlacementSolution(boolean[][] occupied, ArrayList itemsToPlace, + boolean ignoreMove) { + this.occupied = occupied; + this.itemsToPlace = itemsToPlace; + this.ignoreMove = ignoreMove; + + // Sort the items such that larger widgets appear first followed by 1x1 items + Collections.sort(this.itemsToPlace); + } + + public void find() { + find(0, 0, 0, new ArrayList()); + } + + /** + * Recursively finds a placement for the provided items. + * @param index the position in {@link #itemsToPlace} to start looking at. + * @param weightLoss total weight loss upto this point + * @param moveCost total move cost upto this point + * @param itemsPlaced all the items already placed upto this point + */ + public void find(int index, float weightLoss, float moveCost, + ArrayList itemsPlaced) { + if ((weightLoss >= lowestWeightLoss) || + ((weightLoss == lowestWeightLoss) && (moveCost >= lowestMoveCost))) { + // Abort, as we already have a better solution. + return; + + } else if (index >= itemsToPlace.size()) { + // End loop. + lowestWeightLoss = weightLoss; + lowestMoveCost = moveCost; + + // Keep a deep copy of current configuration as it can change during recursion. + finalPlacedItems = deepCopy(itemsPlaced); + return; + } + + DbEntry me = itemsToPlace.get(index); + int myX = me.cellX; + int myY = me.cellY; + + // List of items to pass over if this item was placed. + ArrayList itemsIncludingMe = new ArrayList<>(itemsPlaced.size() + 1); + itemsIncludingMe.addAll(itemsPlaced); + itemsIncludingMe.add(me); + + if (me.spanX > 1 || me.spanY > 1) { + // If the current item is a widget (and it greater than 1x1), try to place it at + // all possible positions. This is because a widget placed at one position can + // affect the placement of a different widget. + int myW = me.spanX; + int myH = me.spanY; + + for (int y = 0; y < mTrgY; y++) { + for (int x = 0; x < mTrgX; x++) { + float newMoveCost = moveCost; + if (x != myX) { + me.cellX = x; + newMoveCost ++; + } + if (y != myY) { + me.cellY = y; + newMoveCost ++; + } + if (ignoreMove) { + newMoveCost = moveCost; + } + + if (isVacant(occupied, x, y, myW, myH)) { + // place at this position and continue search. + markCells(occupied, me, true); + find(index + 1, weightLoss, newMoveCost, itemsIncludingMe); + markCells(occupied, me, false); + } + + // Try resizing horizontally + if (myW > me.minSpanX && isVacant(occupied, x, y, myW - 1, myH)) { + me.spanX --; + markCells(occupied, me, true); + // 1 extra move cost + find(index + 1, weightLoss, newMoveCost + 1, itemsIncludingMe); + markCells(occupied, me, false); + me.spanX ++; + } + + // Try resizing vertically + if (myH > me.minSpanY && isVacant(occupied, x, y, myW, myH - 1)) { + me.spanY --; + markCells(occupied, me, true); + // 1 extra move cost + find(index + 1, weightLoss, newMoveCost + 1, itemsIncludingMe); + markCells(occupied, me, false); + me.spanY ++; + } + + // Try resizing horizontally & vertically + if (myH > me.minSpanY && myW > me.minSpanX && + isVacant(occupied, x, y, myW - 1, myH - 1)) { + me.spanX --; + me.spanY --; + markCells(occupied, me, true); + // 2 extra move cost + find(index + 1, weightLoss, newMoveCost + 2, itemsIncludingMe); + markCells(occupied, me, false); + me.spanX ++; + me.spanY ++; + } + me.cellX = myX; + me.cellY = myY; + } + } + + // Finally also try a solution when this item is not included. Trying it in the end + // causes it to get skipped in most cases due to higher weight loss, and prevents + // unnecessary deep copies of various configurations. + find(index + 1, weightLoss + me.weight, moveCost, itemsPlaced); + } else { + // Since this is a 1x1 item and all the following items are also 1x1, just place + // it at 'the most appropriate position' and hope for the best. + // The most appropriate position: one with lease straight line distance + int newDistance = Integer.MAX_VALUE; + int newX = Integer.MAX_VALUE, newY = Integer.MAX_VALUE; + + for (int y = 0; y < mTrgY; y++) { + for (int x = 0; x < mTrgX; x++) { + if (!occupied[x][y]) { + int dist = ignoreMove ? 0 : + ((me.cellX - x) * (me.cellX - x) + (me.cellY - y) * (me.cellY - y)); + if (dist < newDistance) { + newX = x; + newY = y; + newDistance = dist; + } + } + } + } + + if (newX < mTrgX && newY < mTrgY) { + float newMoveCost = moveCost; + if (newX != myX) { + me.cellX = newX; + newMoveCost ++; + } + if (newY != myY) { + me.cellY = newY; + newMoveCost ++; + } + if (ignoreMove) { + newMoveCost = moveCost; + } + markCells(occupied, me, true); + find(index + 1, weightLoss, newMoveCost, itemsIncludingMe); + markCells(occupied, me, false); + me.cellX = myX; + me.cellY = myY; + + // Try to find a solution without this item, only if + // 1) there was at least one space, i.e., we were able to place this item + // 2) if the next item has the same weight (all items are already sorted), as + // if it has lower weight, that solution will automatically get discarded. + // 3) ignoreMove false otherwise, move cost is ignored and the weight will + // anyway be same. + if (index + 1 < itemsToPlace.size() + && itemsToPlace.get(index + 1).weight >= me.weight && !ignoreMove) { + find(index + 1, weightLoss + me.weight, moveCost, itemsPlaced); + } + } else { + // No more space. Jump to the end. + for (int i = index + 1; i < itemsToPlace.size(); i++) { + weightLoss += itemsToPlace.get(i).weight; + } + find(itemsToPlace.size(), weightLoss + me.weight, moveCost, itemsPlaced); + } + } + } + } + + /** + * Loads entries for a particular screen id. + */ + public ArrayList loadEntries(long screen) { + Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI, + new String[] { + Favorites._ID, // 0 + Favorites.ITEM_TYPE, // 1 + Favorites.CELLX, // 2 + Favorites.CELLY, // 3 + Favorites.SPANX, // 4 + Favorites.SPANY, // 5 + Favorites.INTENT, // 6 + Favorites.APPWIDGET_PROVIDER}, // 7 + Favorites.CONTAINER + " = " + Favorites.CONTAINER_DESKTOP + + " AND " + Favorites.SCREEN + " = " + screen, null, null, null); + + final int indexId = c.getColumnIndexOrThrow(Favorites._ID); + final int indexItemType = c.getColumnIndexOrThrow(Favorites.ITEM_TYPE); + final int indexCellX = c.getColumnIndexOrThrow(Favorites.CELLX); + final int indexCellY = c.getColumnIndexOrThrow(Favorites.CELLY); + final int indexSpanX = c.getColumnIndexOrThrow(Favorites.SPANX); + final int indexSpanY = c.getColumnIndexOrThrow(Favorites.SPANY); + final int indexIntent = c.getColumnIndexOrThrow(Favorites.INTENT); + final int indexAppWidgetProvider = c.getColumnIndexOrThrow(Favorites.APPWIDGET_PROVIDER); + + ArrayList entries = new ArrayList<>(); + while (c.moveToNext()) { + DbEntry entry = new DbEntry(); + entry.id = c.getLong(indexId); + entry.itemType = c.getInt(indexItemType); + entry.cellX = c.getInt(indexCellX); + entry.cellY = c.getInt(indexCellY); + entry.spanX = c.getInt(indexSpanX); + entry.spanY = c.getInt(indexSpanY); + entry.screenId = screen; + + try { + // calculate weight + switch (entry.itemType) { + case Favorites.ITEM_TYPE_SHORTCUT: + case Favorites.ITEM_TYPE_APPLICATION: { + verifyIntent(c.getString(indexIntent)); + entry.weight = entry.itemType == Favorites.ITEM_TYPE_SHORTCUT + ? WT_SHORTCUT : WT_APPLICATION; + break; + } + case Favorites.ITEM_TYPE_APPWIDGET: { + String provider = c.getString(indexAppWidgetProvider); + ComponentName cn = ComponentName.unflattenFromString(provider); + verifyPackage(cn.getPackageName()); + entry.weight = Math.max(WT_WIDGET_MIN, WT_WIDGET_FACTOR + * entry.spanX * entry.spanY); + + // Migration happens for current user only. + LauncherAppWidgetProviderInfo pInfo = LauncherModel.getProviderInfo( + mContext, cn, UserHandleCompat.myUserHandle()); + Point spans = pInfo == null ? + mWidgetMinSize.get(provider) : pInfo.getMinSpans(mIdp, mContext); + if (spans != null) { + entry.minSpanX = spans.x > 0 ? spans.x : entry.spanX; + entry.minSpanY = spans.y > 0 ? spans.y : entry.spanY; + } else { + // Assume that the widget be resized down to 2x2 + entry.minSpanX = entry.minSpanY = 2; + } + + if (entry.minSpanX > mTrgX || entry.minSpanY > mTrgY) { + throw new Exception("Widget can't be resized down to fit the grid"); + } + break; + } + case Favorites.ITEM_TYPE_FOLDER: { + int total = getFolderItemsCount(entry.id); + if (total == 0) { + throw new Exception("Folder is empty"); + } + entry.weight = WT_FOLDER_FACTOR * total; + break; + } + default: + throw new Exception("Invalid item type"); + } + } catch (Exception e) { + if (DEBUG) { + Log.d(TAG, "Removing item " + entry.id, e); + } + mEntryToRemove.add(entry.id); + continue; + } + + entries.add(entry); + } + return entries; + } + + /** + * @return the number of valid items in the folder. + */ + private int getFolderItemsCount(long folderId) { + Cursor c = mContext.getContentResolver().query(LauncherSettings.Favorites.CONTENT_URI, + new String[] {Favorites._ID, Favorites.INTENT}, + Favorites.CONTAINER + " = " + folderId, null, null, null); + + int total = 0; + while (c.moveToNext()) { + try { + verifyIntent(c.getString(1)); + total++; + } catch (Exception e) { + mEntryToRemove.add(c.getLong(0)); + } + } + + return total; + } + + /** + * Verifies if the intent should be restored. + */ + private void verifyIntent(String intentStr) throws Exception { + Intent intent = Intent.parseUri(intentStr, 0); + if (intent.getComponent() != null) { + verifyPackage(intent.getComponent().getPackageName()); + } else if (intent.getPackage() != null) { + // Only verify package if the component was null. + verifyPackage(intent.getPackage()); + } + } + + /** + * Verifies if the package should be restored + */ + private void verifyPackage(String packageName) throws Exception { + if (!mValidPackages.contains(packageName)) { + throw new Exception("Package not available"); + } + } + + private static class DbEntry extends ItemInfo implements Comparable { + + public float weight; + + public DbEntry() { } + + public DbEntry copy() { + DbEntry entry = new DbEntry(); + entry.copyFrom(this); + entry.weight = weight; + entry.minSpanX = minSpanX; + entry.minSpanY = minSpanY; + return entry; + } + + /** + * Comparator such that larger widgets come first, followed by all 1x1 items + * based on their weights. + */ + @Override + public int compareTo(DbEntry another) { + if (itemType == Favorites.ITEM_TYPE_APPWIDGET) { + if (another.itemType == Favorites.ITEM_TYPE_APPWIDGET) { + return another.spanY * another.spanX - spanX * spanY; + } else { + return -1; + } + } else if (another.itemType == Favorites.ITEM_TYPE_APPWIDGET) { + return 1; + } else { + // Place higher weight before lower weight. + return Float.compare(another.weight, weight); + } + } + + public boolean columnsSame(DbEntry org) { + return org.cellX == cellX && org.cellY == cellY && org.spanX == spanX && + org.spanY == spanY && org.screenId == screenId; + } + + public void addToContentValues(ContentValues values) { + values.put(LauncherSettings.Favorites.SCREEN, screenId); + values.put(LauncherSettings.Favorites.CELLX, cellX); + values.put(LauncherSettings.Favorites.CELLY, cellY); + values.put(LauncherSettings.Favorites.SPANX, spanX); + values.put(LauncherSettings.Favorites.SPANY, spanY); + } + } + + @Thunk static ArrayList deepCopy(ArrayList src) { + ArrayList dup = new ArrayList(src.size()); + for (DbEntry e : src) { + dup.add(e.copy()); + } + return dup; + } + + private static Point parsePoint(String point) { + String[] split = point.split(","); + return new Point(Integer.parseInt(split[0]), Integer.parseInt(split[1])); + } + + public static void markForMigration(Context context, int srcX, int srcY, + HashSet widgets) { + prefs(context).edit() + .putString(KEY_MIGRATION_SOURCE_SIZE, srcX + "," + srcY) + .putStringSet(KEY_MIGRATION_WIDGET_MINSIZE, widgets) + .apply(); + } + + public static boolean shouldRunTask(Context context) { + return !TextUtils.isEmpty(prefs(context).getString(KEY_MIGRATION_SOURCE_SIZE, "")); + } + + public static void clearFlags(Context context) { + prefs(context).edit().remove(KEY_MIGRATION_SOURCE_SIZE) + .remove(KEY_MIGRATION_WIDGET_MINSIZE).commit(); + } + + private static SharedPreferences prefs(Context context) { + return context.getSharedPreferences(LauncherAppState.getSharedPreferencesKey(), + Context.MODE_PRIVATE); + } +} -- cgit v1.2.3 From e8f1d047b1b788bc9884be2417e7aa0cec7e8ae8 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 31 Jul 2015 12:39:57 -0700 Subject: Fixing issue with flash during overview transition. - This is due to the TransitionDrawable which does not actually start an animation until it is first drawn. This workaround will just immediately reset the transition if it is not currently visible instead of animating (which is actually deferred until the next animation into overview mode). Bug: 22414257 Change-Id: Id481303d0c99a20c1d16396c024ab50303f45576 --- src/com/android/launcher3/CellLayout.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 809688712..b875d22e6 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -211,6 +211,7 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { mBackground = (TransitionDrawable) res.getDrawable(R.drawable.bg_screenpanel); mBackground.setCallback(this); + mBackground.setAlpha((int) (mBackgroundAlpha * 255)); mReorderPreviewAnimationMagnitude = (REORDER_PREVIEW_MAGNITUDE * grid.iconSizePx); @@ -414,7 +415,11 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { if (mIsDragOverlapping) { mBackground.startTransition(BACKGROUND_ACTIVATE_DURATION); } else { - mBackground.reverseTransition(BACKGROUND_ACTIVATE_DURATION); + if (mBackgroundAlpha > 0f) { + mBackground.reverseTransition(BACKGROUND_ACTIVATE_DURATION); + } else { + mBackground.resetTransition(); + } } invalidate(); } -- cgit v1.2.3 From d934e0b0b7b60c9457fd0eb615355c16bac1a285 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 31 Jul 2015 12:40:57 -0700 Subject: Enabling logging for migration task Bug: 22353460 Change-Id: I8a9a8ea0d5523acb6d2376920535a9f4f519525d --- src/com/android/launcher3/LauncherModel.java | 5 ++++- src/com/android/launcher3/model/MigrateFromRestoreTask.java | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 7e75f9793..41f36eb04 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -27,7 +27,6 @@ import android.content.Context; import android.content.Intent; import android.content.Intent.ShortcutIconResource; import android.content.IntentFilter; -import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; @@ -1761,6 +1760,8 @@ public class LauncherModel extends BroadcastReceiver if (MigrateFromRestoreTask.shouldRunTask(mContext)) { + long migrationStartTime = System.currentTimeMillis(); + Log.v(TAG, "Starting workspace migration after restore"); try { MigrateFromRestoreTask task = new MigrateFromRestoreTask(mContext); // Clear the flags before starting the task, so that we do not run the task @@ -1773,6 +1774,8 @@ public class LauncherModel extends BroadcastReceiver // Clear workspace. mFlags = mFlags | LOADER_FLAG_CLEAR_WORKSPACE; } + Log.v(TAG, "Workspace migration completed in " + + (System.currentTimeMillis() - migrationStartTime)); } if ((mFlags & LOADER_FLAG_CLEAR_WORKSPACE) != 0) { diff --git a/src/com/android/launcher3/model/MigrateFromRestoreTask.java b/src/com/android/launcher3/model/MigrateFromRestoreTask.java index cb90c8bc9..8d4472fd1 100644 --- a/src/com/android/launcher3/model/MigrateFromRestoreTask.java +++ b/src/com/android/launcher3/model/MigrateFromRestoreTask.java @@ -38,7 +38,7 @@ import java.util.HashSet; public class MigrateFromRestoreTask { private static final String TAG = "MigrateFromRestoreTask"; - private static final boolean DEBUG = false; + private static final boolean DEBUG = true; private static final String KEY_MIGRATION_SOURCE_SIZE = "migration_restore_src_size"; private static final String KEY_MIGRATION_WIDGET_MINSIZE = "migration_widget_min_size"; -- cgit v1.2.3 From a547c4516c1a2dfd87f3466fccffd5ca6c5cab8c Mon Sep 17 00:00:00 2001 From: Adam Cohen Date: Fri, 31 Jul 2015 21:06:10 +0000 Subject: Revert "Add proto flag "javanano_use_deprecated_package" to avoid build breakage" This reverts commit cb7674118c6fa6849e657fb8fea25c8fd93477cc. Change-Id: I831abe3746be49fd164046655e8c5e059bae074f --- protos/backup.proto | 1 - 1 file changed, 1 deletion(-) diff --git a/protos/backup.proto b/protos/backup.proto index e1af696d4..f3ad0b61f 100644 --- a/protos/backup.proto +++ b/protos/backup.proto @@ -18,7 +18,6 @@ syntax = "proto2"; package launcher_backup; -option javanano_use_deprecated_package = true; option java_package = "com.android.launcher3.backup"; option java_outer_classname = "BackupProtos"; -- cgit v1.2.3 From 6eeab68fd4a5ba51e32717b18c40e9bea8b38e97 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 16 Jul 2015 12:21:00 -0700 Subject: Fixing drag outline positions for folder over hotseat Bug: 22506247 Change-Id: Ia2508307554089205fd678987454e81cb811a59b (cherry picked from commit 92bce4316422c69ee26e6ece204fbf1499753086) --- src/com/android/launcher3/Workspace.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 267787be8..086934773 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -2276,6 +2276,8 @@ public class Workspace extends PagedView dragRect = new Rect(left, top, right, bottom); } else if (child instanceof FolderIcon) { int previewSize = grid.folderIconSizePx; + dragVisualizeOffset = new Point(-padding.get() / 2, + padding.get() / 2 - child.getPaddingTop()); dragRect = new Rect(0, child.getPaddingTop(), child.getWidth(), previewSize); } -- cgit v1.2.3 From 88fa741e50760f9da78cba4a766172f23773bb87 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 3 Aug 2015 14:25:28 -0700 Subject: Remove handler for searchables changed broadcast. Bug: 22515084 --- src/com/android/launcher3/Launcher.java | 2 +- src/com/android/launcher3/LauncherAppState.java | 1 - src/com/android/launcher3/LauncherModel.java | 7 +++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 6648b6e74..15e43b2b9 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -4101,7 +4101,7 @@ public class Launcher extends Activity return mDeviceProfile.getSearchBarBounds(Utilities.isRtl(getResources())); } - public void bindSearchablesChanged() { + public void bindSearchProviderChanged() { if (mSearchDropTargetBar == null) { return; } diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 0b7b1fdc4..0d087c22d 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -96,7 +96,6 @@ public class LauncherAppState { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_LOCALE_CHANGED); filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED); - filter.addAction(SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED); // For handling managed profiles filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED); filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED); diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 0b67310fa..b7fb60a78 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -203,7 +203,7 @@ public class LauncherModel extends BroadcastReceiver public void bindComponentsRemoved(ArrayList packageNames, ArrayList appInfos, UserHandleCompat user, int reason); public void bindAllPackages(WidgetsModel model); - public void bindSearchablesChanged(); + public void bindSearchProviderChanged(); public boolean isAllAppsButtonRank(int rank); public void onPageBoundSynchronously(int page); public void dumpLogsToLocalData(); @@ -1280,11 +1280,10 @@ public class LauncherModel extends BroadcastReceiver if (Intent.ACTION_LOCALE_CHANGED.equals(action)) { // If we have changed locale we need to clear out the labels in all apps/workspace. forceReload(); - } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action) || - SearchManager.INTENT_ACTION_SEARCHABLES_CHANGED.equals(action)) { + } else if (SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED.equals(action)) { Callbacks callbacks = getCallback(); if (callbacks != null) { - callbacks.bindSearchablesChanged(); + callbacks.bindSearchProviderChanged(); } } else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED.equals(action) || LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) { -- cgit v1.2.3 From 233ee964a9ecf419a3e8330a67456d422879132d Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 3 Aug 2015 13:05:01 -0700 Subject: Calculating widget minSpans and spans statically/independent of orientation > Filtering the widget list and excluding widgets which dont fit the grid > setting minSpans for the widget item when binding. Bug: 22541314 Bug: 22559137 Change-Id: Ieda48b56c95bee0c7ec71dd691af7e23e2d43db6 --- .../android/launcher3/AppWidgetResizeFrame.java | 4 +- src/com/android/launcher3/CellLayout.java | 60 --------------- src/com/android/launcher3/Launcher.java | 21 +----- .../android/launcher3/LauncherAppWidgetInfo.java | 4 - .../launcher3/LauncherAppWidgetProviderInfo.java | 87 +++++++++++----------- src/com/android/launcher3/WidgetPreviewLoader.java | 4 +- .../launcher3/allapps/AllAppsContainerView.java | 1 - src/com/android/launcher3/model/WidgetsModel.java | 28 ++++++- .../launcher3/widget/PendingAddWidgetInfo.java | 16 +--- src/com/android/launcher3/widget/WidgetCell.java | 4 +- .../launcher3/widget/WidgetsContainerView.java | 1 - 11 files changed, 81 insertions(+), 149 deletions(-) diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index ea7c22189..e6bf52531 100644 --- a/src/com/android/launcher3/AppWidgetResizeFrame.java +++ b/src/com/android/launcher3/AppWidgetResizeFrame.java @@ -75,8 +75,8 @@ public class AppWidgetResizeFrame extends FrameLayout { mResizeMode = info.resizeMode; mDragLayer = dragLayer; - mMinHSpan = info.getMinSpanX(mLauncher); - mMinVSpan = info.getMinSpanY(mLauncher); + mMinHSpan = info.minSpanX; + mMinVSpan = info.minSpanY; setBackgroundResource(R.drawable.widget_resize_shadow); setForeground(getResources().getDrawable(R.drawable.widget_resize_frame)); diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index b875d22e6..84e2d49c2 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -54,7 +54,6 @@ import com.android.launcher3.accessibility.DragAndDropAccessibilityDelegate; import com.android.launcher3.accessibility.FolderAccessibilityHelper; import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper; import com.android.launcher3.util.Thunk; -import com.android.launcher3.widget.PendingAddWidgetInfo; import java.util.ArrayList; import java.util.Arrays; @@ -2686,65 +2685,6 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler { resultRect.set(x, y, x + width, y + height); } - /** - * Computes the required horizontal and vertical cell spans to always - * fit the given rectangle. - * - * @param width Width in pixels - * @param height Height in pixels - * @param result An array of length 2 in which to store the result (may be null). - */ - public static int[] rectToCell(Launcher launcher, int width, int height, int[] result) { - return rectToCell(launcher.getDeviceProfile(), launcher, width, height, result); - } - - public static int[] rectToCell(DeviceProfile grid, Context context, int width, int height, - int[] result) { - Rect padding = grid.getWorkspacePadding(Utilities.isRtl(context.getResources())); - - // Always assume we're working with the smallest span to make sure we - // reserve enough space in both orientations. - int parentWidth = DeviceProfile.calculateCellWidth(grid.widthPx - - padding.left - padding.right, (int) grid.inv.numColumns); - int parentHeight = DeviceProfile.calculateCellHeight(grid.heightPx - - padding.top - padding.bottom, (int) grid.inv.numRows); - int smallerSize = Math.min(parentWidth, parentHeight); - - // Always round up to next largest cell - int spanX = (int) Math.ceil(width / (float) smallerSize); - int spanY = (int) Math.ceil(height / (float) smallerSize); - - if (result == null) { - return new int[] { spanX, spanY }; - } - result[0] = spanX; - result[1] = spanY; - return result; - } - - /** - * Calculate the grid spans needed to fit given item - */ - public void calculateSpans(ItemInfo info) { - final int minWidth; - final int minHeight; - - if (info instanceof LauncherAppWidgetInfo) { - minWidth = ((LauncherAppWidgetInfo) info).minWidth; - minHeight = ((LauncherAppWidgetInfo) info).minHeight; - } else if (info instanceof PendingAddWidgetInfo) { - minWidth = ((PendingAddWidgetInfo) info).minWidth; - minHeight = ((PendingAddWidgetInfo) info).minHeight; - } else { - // It's not a widget, so it must be 1x1 - info.spanX = info.spanY = 1; - return; - } - int[] spans = rectToCell(mLauncher, minWidth, minHeight, null); - info.spanX = spans[0]; - info.spanY = spans[1]; - } - private void clearOccupiedCells() { for (int x = 0; x < mCountX; x++) { for (int y = 0; y < mCountY; y++) { diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 6648b6e74..a6c728987 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1553,23 +1553,6 @@ public class Launcher extends Activity } } - private int[] getSpanForWidget(ComponentName component, int minWidth, int minHeight) { - Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(this, component, null); - // We want to account for the extra amount of padding that we are adding to the widget - // to ensure that it gets the full amount of space that it has requested - int requiredWidth = minWidth + padding.left + padding.right; - int requiredHeight = minHeight + padding.top + padding.bottom; - return CellLayout.rectToCell(this, requiredWidth, requiredHeight, null); - } - - public int[] getSpanForWidget(AppWidgetProviderInfo info) { - return getSpanForWidget(info.provider, info.minWidth, info.minHeight); - } - - public int[] getMinSpanForWidget(AppWidgetProviderInfo info) { - return getSpanForWidget(info.provider, info.minResizeWidth, info.minResizeHeight); - } - /** * Add a widget to the workspace. * @@ -2218,7 +2201,7 @@ public class Launcher extends Activity mPendingAddInfo.screenId = -1; mPendingAddInfo.cellX = mPendingAddInfo.cellY = -1; mPendingAddInfo.spanX = mPendingAddInfo.spanY = -1; - mPendingAddInfo.minSpanX = mPendingAddInfo.minSpanY = -1; + mPendingAddInfo.minSpanX = mPendingAddInfo.minSpanY = 1; mPendingAddInfo.dropPos = null; } @@ -3957,6 +3940,8 @@ public class Launcher extends Activity } item.hostView = mAppWidgetHost.createView(this, appWidgetId, appWidgetInfo); + item.minSpanX = appWidgetInfo.minSpanX; + item.minSpanY = appWidgetInfo.minSpanY; } else { appWidgetInfo = null; PendingAppWidgetHostView view = new PendingAppWidgetHostView(this, item, diff --git a/src/com/android/launcher3/LauncherAppWidgetInfo.java b/src/com/android/launcher3/LauncherAppWidgetInfo.java index aad18b578..882f7e202 100644 --- a/src/com/android/launcher3/LauncherAppWidgetInfo.java +++ b/src/com/android/launcher3/LauncherAppWidgetInfo.java @@ -68,10 +68,6 @@ public class LauncherAppWidgetInfo extends ItemInfo { ComponentName providerName; - // TODO: Are these necessary here? - int minWidth = -1; - int minHeight = -1; - /** * Indicates the restore status of the widget. */ diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java index 9ba78530d..71a08a853 100644 --- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java +++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java @@ -1,11 +1,13 @@ package com.android.launcher3; import android.annotation.TargetApi; +import android.appwidget.AppWidgetHostView; import android.appwidget.AppWidgetProviderInfo; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.Point; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Parcel; @@ -20,10 +22,10 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo { public boolean isCustomWidget = false; - private int mSpanX = -1; - private int mSpanY = -1; - private int mMinSpanX = -1; - private int mMinSpanY = -1; + public int spanX; + public int spanY; + public int minSpanX; + public int minSpanY; public static LauncherAppWidgetProviderInfo fromProviderInfo(Context context, AppWidgetProviderInfo info) { @@ -42,6 +44,7 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo { public LauncherAppWidgetProviderInfo(Parcel in) { super(in); + initSpans(); } public LauncherAppWidgetProviderInfo(Context context, CustomAppWidget widget) { @@ -53,6 +56,41 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo { previewImage = widget.getPreviewImage(); initialLayout = widget.getWidgetLayout(); resizeMode = widget.getResizeMode(); + initSpans(); + } + + private void initSpans() { + LauncherAppState app = LauncherAppState.getInstance(); + InvariantDeviceProfile idp = app.getInvariantDeviceProfile(); + + // We only care out the cell size, which is independent of the the layout direction. + Rect paddingLand = idp.landscapeProfile.getWorkspacePadding(false /* isLayoutRtl */); + Rect paddingPort = idp.portraitProfile.getWorkspacePadding(false /* isLayoutRtl */); + + // Always assume we're working with the smallest span to make sure we + // reserve enough space in both orientations. + float smallestCellWidth = DeviceProfile.calculateCellWidth(Math.min( + idp.landscapeProfile.widthPx - paddingLand.left - paddingLand.right, + idp.portraitProfile.widthPx - paddingPort.left - paddingPort.right), + idp.numColumns); + float smallestCellHeight = DeviceProfile.calculateCellWidth(Math.min( + idp.landscapeProfile.heightPx - paddingLand.top - paddingLand.bottom, + idp.portraitProfile.heightPx - paddingPort.top - paddingPort.bottom), + idp.numRows); + + // We want to account for the extra amount of padding that we are adding to the widget + // to ensure that it gets the full amount of space that it has requested. + Rect widgetPadding = AppWidgetHostView.getDefaultPaddingForWidget( + app.getContext(), provider, null); + spanX = Math.max(1, (int) Math.ceil( + (minWidth + widgetPadding.left + widgetPadding.right) / smallestCellWidth)); + spanY = Math.max(1, (int) Math.ceil( + (minHeight + widgetPadding.top + widgetPadding.bottom) / smallestCellHeight)); + + minSpanX = Math.max(1, (int) Math.ceil( + (minResizeWidth + widgetPadding.left + widgetPadding.right) / smallestCellWidth)); + minSpanY = Math.max(1, (int) Math.ceil( + (minResizeHeight + widgetPadding.top + widgetPadding.bottom) / smallestCellHeight)); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) @@ -80,46 +118,9 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo { provider.toString(), provider.getPackageName(), provider.getShortClassName(), getLabel(pm)); } - public int getSpanX(Launcher launcher) { - lazyLoadSpans(launcher); - return mSpanX; - } - - public int getSpanY(Launcher launcher) { - lazyLoadSpans(launcher); - return mSpanY; - } - - public int getMinSpanX(Launcher launcher) { - lazyLoadSpans(launcher); - return mMinSpanX; - } - - public int getMinSpanY(Launcher launcher) { - lazyLoadSpans(launcher); - return mMinSpanY; - } - - private void lazyLoadSpans(Launcher launcher) { - if (mSpanX < 0 || mSpanY < 0 || mMinSpanX < 0 || mMinSpanY < 0) { - int[] minResizeSpan = launcher.getMinSpanForWidget(this); - int[] span = launcher.getSpanForWidget(this); - - mSpanX = span[0]; - mSpanY = span[1]; - mMinSpanX = minResizeSpan[0]; - mMinSpanY = minResizeSpan[1]; - } - } - public Point getMinSpans(InvariantDeviceProfile idp, Context context) { - // Calculate the spans corresponding to any one of the orientations as it should not change - // based on orientation. - // TODO: Use the max of both profiles - int[] minSpans = CellLayout.rectToCell( - idp.portraitProfile, context, minResizeWidth, minResizeHeight, null); return new Point( - (resizeMode & RESIZE_HORIZONTAL) != 0 ? minSpans[0] : -1, - (resizeMode & RESIZE_VERTICAL) != 0 ? minSpans[1] : -1); + (resizeMode & RESIZE_HORIZONTAL) != 0 ? minSpanX : -1, + (resizeMode & RESIZE_VERTICAL) != 0 ? minSpanY : -1); } } diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java index 2a8053d52..1fb795add 100644 --- a/src/com/android/launcher3/WidgetPreviewLoader.java +++ b/src/com/android/launcher3/WidgetPreviewLoader.java @@ -361,8 +361,8 @@ public class WidgetPreviewLoader { } final boolean widgetPreviewExists = (drawable != null); - final int spanX = info.getSpanX(launcher) < 1 ? 1 : info.getSpanX(launcher); - final int spanY = info.getSpanY(launcher) < 1 ? 1 : info.getSpanY(launcher); + final int spanX = info.spanX; + final int spanY = info.spanY; int previewWidth; int previewHeight; diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 67d572819..010b2cb48 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -528,7 +528,6 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen); ItemInfo itemInfo = (ItemInfo) d.dragInfo; if (layout != null) { - layout.calculateSpans(itemInfo); showOutOfSpaceMessage = !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY); } diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java index cabff148f..eef4f9173 100644 --- a/src/com/android/launcher3/model/WidgetsModel.java +++ b/src/com/android/launcher3/model/WidgetsModel.java @@ -8,6 +8,9 @@ import android.util.Log; import com.android.launcher3.AppFilter; import com.android.launcher3.IconCache; +import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.Utilities; import com.android.launcher3.compat.AlphabeticIndexCompat; @@ -40,7 +43,7 @@ public class WidgetsModel { private final AppWidgetManagerCompat mAppWidgetMgr; private final WidgetsAndShortcutNameComparator mWidgetAndShortcutNameComparator; - private final Comparator mAppNameComparator; + private final Comparator mAppNameComparator; private final IconCache mIconCache; private final AppFilter mAppFilter; private AlphabeticIndexCompat mIndexer; @@ -54,6 +57,7 @@ public class WidgetsModel { mIndexer = new AlphabeticIndexCompat(context); } + @SuppressWarnings("unchecked") private WidgetsModel(WidgetsModel model) { mAppWidgetMgr = model.mAppWidgetMgr; mPackageItemInfos = (ArrayList) model.mPackageItemInfos.clone(); @@ -105,6 +109,8 @@ public class WidgetsModel { mPackageItemInfos.clear(); mWidgetAndShortcutNameComparator.reset(); + InvariantDeviceProfile idp = LauncherAppState.getInstance().getInvariantDeviceProfile(); + // add and update. for (Object o: rawWidgetsShortcuts) { String packageName = ""; @@ -112,9 +118,23 @@ public class WidgetsModel { ComponentName componentName = null; if (o instanceof LauncherAppWidgetProviderInfo) { LauncherAppWidgetProviderInfo widgetInfo = (LauncherAppWidgetProviderInfo) o; - componentName = widgetInfo.provider; - packageName = widgetInfo.provider.getPackageName(); - userHandle = mAppWidgetMgr.getUser(widgetInfo); + + // Ensure that all widgets we show can be added on a workspace of this size + int minSpanX = Math.min(widgetInfo.spanX, widgetInfo.minSpanX); + int minSpanY = Math.min(widgetInfo.spanY, widgetInfo.minSpanY); + if (minSpanX <= (int) idp.numColumns && + minSpanY <= (int) idp.numRows) { + componentName = widgetInfo.provider; + packageName = widgetInfo.provider.getPackageName(); + userHandle = mAppWidgetMgr.getUser(widgetInfo); + } else { + if (DEBUG) { + Log.d(TAG, String.format( + "Widget %s : (%d X %d) can't fit on this device", + widgetInfo.provider, minSpanX, minSpanY)); + } + continue; + } } else if (o instanceof ResolveInfo) { ResolveInfo resolveInfo = (ResolveInfo) o; componentName = new ComponentName(resolveInfo.activityInfo.packageName, diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java index 758287af3..fcb714ff1 100644 --- a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java +++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java @@ -31,10 +31,6 @@ import com.android.launcher3.compat.AppWidgetManagerCompat; * @see {@link PendingAddItemInfo} */ public class PendingAddWidgetInfo extends PendingAddItemInfo { - public int minWidth; - public int minHeight; - public int minResizeWidth; - public int minResizeHeight; public int previewImage; public int icon; public LauncherAppWidgetProviderInfo info; @@ -50,17 +46,13 @@ public class PendingAddWidgetInfo extends PendingAddItemInfo { this.info = i; user = AppWidgetManagerCompat.getInstance(launcher).getUser(i); componentName = i.provider; - minWidth = i.minWidth; - minHeight = i.minHeight; - minResizeWidth = i.minResizeWidth; - minResizeHeight = i.minResizeHeight; previewImage = i.previewImage; icon = i.icon; - spanX = i.getSpanX(launcher); - spanY = i.getSpanY(launcher); - minSpanX = i.getMinSpanX(launcher); - minSpanY = i.getMinSpanY(launcher); + spanX = i.spanX; + spanY = i.spanY; + minSpanX = i.minSpanX; + minSpanY = i.minSpanY; } public boolean isCustomWidget() { diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java index 7496ea2ef..94bbd929f 100644 --- a/src/com/android/launcher3/widget/WidgetCell.java +++ b/src/com/android/launcher3/widget/WidgetCell.java @@ -146,8 +146,8 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener { mInfo = info; // TODO(hyunyoungs): setup a cache for these labels. mWidgetName.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info)); - int hSpan = Math.min(info.getSpanX(mLauncher), profile.numColumns); - int vSpan = Math.min(info.getSpanY(mLauncher), profile.numRows); + int hSpan = Math.min(info.spanX, profile.numColumns); + int vSpan = Math.min(info.spanY, profile.numRows); mWidgetDims.setText(String.format(mDimensionsFormatString, hSpan, vSpan)); mWidgetPreviewLoader = loader; } diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java index 5afd7c493..0c6ea31bb 100644 --- a/src/com/android/launcher3/widget/WidgetsContainerView.java +++ b/src/com/android/launcher3/widget/WidgetsContainerView.java @@ -319,7 +319,6 @@ public class WidgetsContainerView extends BaseContainerView CellLayout layout = (CellLayout) workspace.getChildAt(currentScreen); ItemInfo itemInfo = (ItemInfo) d.dragInfo; if (layout != null) { - layout.calculateSpans(itemInfo); showOutOfSpaceMessage = !layout.findCellForSpan(null, itemInfo.spanX, itemInfo.spanY); } -- cgit v1.2.3 From 209a859dedba0e8314ee102a760aad78a814ea94 Mon Sep 17 00:00:00 2001 From: Adam Cohen Date: Mon, 3 Aug 2015 16:59:10 -0700 Subject: Fix issue where scroll container shadow didn't fade out Change-Id: I3b0104dea04009819db0375c381b8ff445b76baa --- .../android/launcher3/WallpaperPickerActivity.java | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java index 88dc3e22b..c723b39be 100644 --- a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java +++ b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java @@ -100,6 +100,7 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { @Thunk LinearLayout mWallpapersView; @Thunk HorizontalScrollView mWallpaperScrollContainer; + @Thunk View mWallpaperStrip; @Thunk ActionMode.Callback mActionModeCallback; @Thunk ActionMode mActionMode; @@ -379,6 +380,7 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { mProgressView = findViewById(R.id.loading); mWallpaperScrollContainer = (HorizontalScrollView) findViewById(R.id.wallpaper_scroll_container); + mWallpaperStrip = findViewById(R.id.wallpaper_strip); mCropView.setTouchCallback(new CropView.TouchCallback() { ViewPropertyAnimator mAnim; @Override @@ -386,15 +388,15 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { if (mAnim != null) { mAnim.cancel(); } - if (mWallpaperScrollContainer.getAlpha() == 1f) { + if (mWallpaperStrip.getAlpha() == 1f) { mIgnoreNextTap = true; } - mAnim = mWallpaperScrollContainer.animate(); + mAnim = mWallpaperStrip.animate(); mAnim.alpha(0f) .setDuration(150) .withEndAction(new Runnable() { public void run() { - mWallpaperScrollContainer.setVisibility(View.INVISIBLE); + mWallpaperStrip.setVisibility(View.INVISIBLE); } }); mAnim.setInterpolator(new AccelerateInterpolator(0.75f)); @@ -412,8 +414,8 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { if (mAnim != null) { mAnim.cancel(); } - mWallpaperScrollContainer.setVisibility(View.VISIBLE); - mAnim = mWallpaperScrollContainer.animate(); + mWallpaperStrip.setVisibility(View.VISIBLE); + mAnim = mWallpaperStrip.animate(); mAnim.alpha(1f) .setDuration(150) .setInterpolator(new DecelerateInterpolator(0.75f)); @@ -713,10 +715,10 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { public void onStop() { super.onStop(); - mWallpaperScrollContainer = (HorizontalScrollView) findViewById(R.id.wallpaper_scroll_container); - if (mWallpaperScrollContainer.getAlpha() < 1f) { - mWallpaperScrollContainer.setAlpha(1f); - mWallpaperScrollContainer.setVisibility(View.VISIBLE); + mWallpaperStrip = findViewById(R.id.wallpaper_strip); + if (mWallpaperStrip.getAlpha() < 1f) { + mWallpaperStrip.setAlpha(1f); + mWallpaperStrip.setVisibility(View.VISIBLE); } } -- cgit v1.2.3 From 912bdfcffa04f8917ff56cc4e059208c13cbe29c Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 3 Aug 2015 19:09:55 -0700 Subject: Replacing exception with a log, when uninstalling an app leads to an illegal state Bug: 22491055 Change-Id: Iaf5fe20b717102bdb0a5442dcc33efea30c50d47 --- src/com/android/launcher3/Workspace.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 086934773..662eabc7c 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -3768,7 +3768,11 @@ public class Workspace extends PagedView if (parentCell != null) { parentCell.removeView(v); } else if (LauncherAppState.isDogfoodBuild()) { - throw new NullPointerException("mDragInfo.cell has null parent"); + // When an app is uninstalled using the drop target, we wait until resume to remove + // the icon. We also remove all the corresponding items from the workspace at + // {@link Launcher#bindComponentsRemoved}. That call can come before or after + // {@link Launcher#mOnResumeCallbacks} depending on how busy the worker thread is. + Log.e(TAG, "mDragInfo.cell has null parent"); } if (v instanceof DropTarget) { mDragController.removeDropTarget((DropTarget) v); -- cgit v1.2.3 From 317698bd012c1930b83bb4e2e47ac9e363fa6c6a Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 29 Jul 2015 11:45:41 -0700 Subject: Loading high resolution icons for first 3 items in a folder > Sometimes a folder gets rearranged, without updating the model, like when an app in uninstalled. In that case, we need to update the icons for folder items, which were previously hidden Bug: 22813360 Change-Id: I99754911c969bf2153efb2948c226c1c69219b88 --- src/com/android/launcher3/BubbleTextView.java | 9 +++++++++ src/com/android/launcher3/Folder.java | 2 +- src/com/android/launcher3/FolderPagedView.java | 4 ++++ src/com/android/launcher3/Launcher.java | 1 + src/com/android/launcher3/LauncherModel.java | 15 +++++++++++++++ src/com/android/launcher3/ShortcutInfo.java | 8 ++++++-- src/com/android/launcher3/Workspace.java | 10 ++++++++++ 7 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index a0be8ea2b..1bcaab519 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -34,11 +34,13 @@ import android.util.SparseArray; import android.util.TypedValue; import android.view.KeyEvent; import android.view.MotionEvent; +import android.view.View; import android.view.ViewConfiguration; import android.view.ViewParent; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.widget.TextView; + import com.android.launcher3.IconCache.IconLoadRequest; import com.android.launcher3.model.PackageItemInfo; @@ -538,6 +540,13 @@ public class BubbleTextView extends TextView } else if (info instanceof ShortcutInfo) { applyFromShortcutInfo((ShortcutInfo) info, LauncherAppState.getInstance().getIconCache()); + if ((info.rank < FolderIcon.NUM_ITEMS_IN_PREVIEW) && (info.container >= 0)) { + View folderIcon = + mLauncher.getWorkspace().getHomescreenIconByItemId(info.container); + if (folderIcon != null) { + folderIcon.invalidate(); + } + } } else if (info instanceof PackageItemInfo) { applyFromPackageItemInfo((PackageItemInfo) info); } diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java index 2e19f6eba..f4fffbe3e 100644 --- a/src/com/android/launcher3/Folder.java +++ b/src/com/android/launcher3/Folder.java @@ -1389,7 +1389,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList } // Compares item position based on rank and position giving priority to the rank. - private static final Comparator ITEM_POS_COMPARATOR = new Comparator() { + public static final Comparator ITEM_POS_COMPARATOR = new Comparator() { @Override public int compare(ItemInfo lhs, ItemInfo rhs) { diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java index f2ec1b68c..cc9c5738a 100644 --- a/src/com/android/launcher3/FolderPagedView.java +++ b/src/com/android/launcher3/FolderPagedView.java @@ -329,6 +329,10 @@ public class FolderPagedView extends PagedView { lp.cellY = info.cellY; currentPage.addViewToCellLayout( v, -1, mFolder.mLauncher.getViewIdForItem(info), lp, true); + + if (rank < FolderIcon.NUM_ITEMS_IN_PREVIEW && v instanceof BubbleTextView) { + ((BubbleTextView) v).verifyHighRes(); + } } rank ++; diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 8b2796048..3b9ebb6d3 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -2662,6 +2662,7 @@ public class Launcher extends Activity throw new IllegalArgumentException("Input must be a FolderIcon"); } + // TODO(sunnygoyal): Re-evaluate this code. FolderIcon folderIcon = (FolderIcon) v; final FolderInfo info = folderIcon.getFolderInfo(); Folder openFolder = mWorkspace.getFolderForTag(info); diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 2e66d34f6..c6fa8acf6 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -2303,6 +2303,21 @@ public class LauncherModel extends BroadcastReceiver } } + // Sort all the folder items and make sure the first 3 items are high resolution. + for (FolderInfo folder : sBgFolders) { + Collections.sort(folder.contents, Folder.ITEM_POS_COMPARATOR); + int pos = 0; + for (ShortcutInfo info : folder.contents) { + if (info.usingLowResIcon) { + info.updateIcon(mIconCache, false); + } + pos ++; + if (pos >= FolderIcon.NUM_ITEMS_IN_PREVIEW) { + break; + } + } + } + if (restoredRows.size() > 0) { // Update restored items that no longer require special handling ContentValues values = new ContentValues(); diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java index 56c0b9d2f..5766cf2f2 100644 --- a/src/com/android/launcher3/ShortcutInfo.java +++ b/src/com/android/launcher3/ShortcutInfo.java @@ -198,13 +198,17 @@ public class ShortcutInfo extends ItemInfo { return mIcon; } - public void updateIcon(IconCache iconCache) { + public void updateIcon(IconCache iconCache, boolean useLowRes) { if (itemType == Favorites.ITEM_TYPE_APPLICATION) { iconCache.getTitleAndIcon(this, promisedIntent != null ? promisedIntent : intent, user, - shouldUseLowResIcon()); + useLowRes); } } + public void updateIcon(IconCache iconCache) { + updateIcon(iconCache, shouldUseLowResIcon()); + } + @Override void onAddToDatabase(Context context, ContentValues values) { super.onAddToDatabase(context, values); diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 662eabc7c..4bd24ef7a 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -4059,6 +4059,16 @@ public class Workspace extends PagedView }); } + public View getHomescreenIconByItemId(final long id) { + return getFirstMatch(new ItemOperator() { + + @Override + public boolean evaluate(ItemInfo info, View v, View parent) { + return info.id == id; + } + }); + } + public View getViewForTag(final Object tag) { return getFirstMatch(new ItemOperator() { -- cgit v1.2.3 From 823fd5090209017a029460e7dbd8ab9d51d013dd Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 4 Aug 2015 11:40:13 -0700 Subject: Creating a cache of users to avoid multiple calls to UserManager Bug: 22805101 Change-Id: I9cd270efd74fdd34a7eb738fc25797e6f1bf2487 --- src/com/android/launcher3/LauncherAppState.java | 3 +++ src/com/android/launcher3/LauncherModel.java | 1 + .../launcher3/compat/UserManagerCompat.java | 25 +++++++++++++++----- .../launcher3/compat/UserManagerCompatV16.java | 4 ++++ .../launcher3/compat/UserManagerCompatV17.java | 24 +++++++++++++++++++ .../launcher3/compat/UserManagerCompatVL.java | 27 ++++++++++++++++++++++ .../launcher3/model/AbstractUserComparator.java | 22 ++---------------- .../android/launcher3/model/AppNameComparator.java | 2 -- 8 files changed, 80 insertions(+), 28 deletions(-) diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index b285a683c..52f85ea42 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -20,11 +20,13 @@ import android.app.SearchManager; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.os.UserManager; import android.util.Log; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.PackageInstallerCompat; +import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.util.Thunk; import java.lang.ref.WeakReference; @@ -100,6 +102,7 @@ public class LauncherAppState { filter.addAction(LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED); sContext.registerReceiver(mModel, filter); + UserManagerCompat.getInstance(sContext).enableAndResetCache(); } /** diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index c6fa8acf6..f029561a3 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -1288,6 +1288,7 @@ public class LauncherModel extends BroadcastReceiver } } else if (LauncherAppsCompat.ACTION_MANAGED_PROFILE_ADDED.equals(action) || LauncherAppsCompat.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) { + UserManagerCompat.getInstance(context).enableAndResetCache(); forceReload(); } } diff --git a/src/com/android/launcher3/compat/UserManagerCompat.java b/src/com/android/launcher3/compat/UserManagerCompat.java index a79d94646..2ff1e7b74 100644 --- a/src/com/android/launcher3/compat/UserManagerCompat.java +++ b/src/com/android/launcher3/compat/UserManagerCompat.java @@ -28,16 +28,29 @@ public abstract class UserManagerCompat { protected UserManagerCompat() { } + private static final Object sInstanceLock = new Object(); + private static UserManagerCompat sInstance; + public static UserManagerCompat getInstance(Context context) { - if (Utilities.isLmpOrAbove()) { - return new UserManagerCompatVL(context); - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - return new UserManagerCompatV17(context); - } else { - return new UserManagerCompatV16(); + synchronized (sInstanceLock) { + if (sInstance == null) { + if (Utilities.isLmpOrAbove()) { + sInstance = new UserManagerCompatVL(context.getApplicationContext()); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + sInstance = new UserManagerCompatV17(context.getApplicationContext()); + } else { + sInstance = new UserManagerCompatV16(); + } + } + return sInstance; } } + /** + * Creates a cache for users. + */ + public abstract void enableAndResetCache(); + public abstract List getUserProfiles(); public abstract long getSerialNumberForUser(UserHandleCompat user); public abstract UserHandleCompat getUserForSerialNumber(long serialNumber); diff --git a/src/com/android/launcher3/compat/UserManagerCompatV16.java b/src/com/android/launcher3/compat/UserManagerCompatV16.java index ffe698c8b..85aee57e8 100644 --- a/src/com/android/launcher3/compat/UserManagerCompatV16.java +++ b/src/com/android/launcher3/compat/UserManagerCompatV16.java @@ -53,4 +53,8 @@ public class UserManagerCompatV16 extends UserManagerCompat { public long getUserCreationTime(UserHandleCompat user) { return 0; } + + @Override + public void enableAndResetCache() { + } } diff --git a/src/com/android/launcher3/compat/UserManagerCompatV17.java b/src/com/android/launcher3/compat/UserManagerCompatV17.java index c42c00c7d..1687569f3 100644 --- a/src/com/android/launcher3/compat/UserManagerCompatV17.java +++ b/src/com/android/launcher3/compat/UserManagerCompatV17.java @@ -21,8 +21,12 @@ import android.content.Context; import android.os.Build; import android.os.UserManager; +import com.android.launcher3.util.LongArrayMap; + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public class UserManagerCompatV17 extends UserManagerCompatV16 { + + protected LongArrayMap mUsers; protected UserManager mUserManager; UserManagerCompatV17(Context context) { @@ -30,11 +34,31 @@ public class UserManagerCompatV17 extends UserManagerCompatV16 { } public long getSerialNumberForUser(UserHandleCompat user) { + synchronized (this) { + if (mUsers != null) { + int index = mUsers.indexOfValue(user); + return (index >= 0) ? mUsers.keyAt(index) : 0; + } + } return mUserManager.getSerialNumberForUser(user.getUser()); } public UserHandleCompat getUserForSerialNumber(long serialNumber) { + synchronized (this) { + if (mUsers != null) { + return mUsers.get(serialNumber); + } + } return UserHandleCompat.fromUser(mUserManager.getUserForSerialNumber(serialNumber)); } + + @Override + public void enableAndResetCache() { + synchronized (this) { + mUsers = new LongArrayMap(); + UserHandleCompat myUser = UserHandleCompat.myUserHandle(); + mUsers.put(mUserManager.getSerialNumberForUser(myUser.getUser()), myUser); + } + } } diff --git a/src/com/android/launcher3/compat/UserManagerCompatVL.java b/src/com/android/launcher3/compat/UserManagerCompatVL.java index dd7a72617..04cd0fdb4 100644 --- a/src/com/android/launcher3/compat/UserManagerCompatVL.java +++ b/src/com/android/launcher3/compat/UserManagerCompatVL.java @@ -24,7 +24,10 @@ import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.UserHandle; + import com.android.launcher3.LauncherAppState; +import com.android.launcher3.util.LongArrayMap; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -42,8 +45,32 @@ public class UserManagerCompatVL extends UserManagerCompatV17 { mContext = context; } + @Override + public void enableAndResetCache() { + synchronized (this) { + mUsers = new LongArrayMap(); + List users = mUserManager.getUserProfiles(); + if (users != null) { + for (UserHandle user : users) { + mUsers.put(mUserManager.getSerialNumberForUser(user), + UserHandleCompat.fromUser(user)); + } + } + } + } + @Override public List getUserProfiles() { + synchronized (this) { + if (mUsers != null) { + List users = new ArrayList<>(); + for (UserHandleCompat user : mUsers) { + users.add(user); + } + return users; + } + } + List users = mUserManager.getUserProfiles(); if (users == null) { return Collections.emptyList(); diff --git a/src/com/android/launcher3/model/AbstractUserComparator.java b/src/com/android/launcher3/model/AbstractUserComparator.java index cf47ce648..bd28560f3 100644 --- a/src/com/android/launcher3/model/AbstractUserComparator.java +++ b/src/com/android/launcher3/model/AbstractUserComparator.java @@ -22,14 +22,12 @@ import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.compat.UserManagerCompat; import java.util.Comparator; -import java.util.HashMap; /** * A comparator to arrange items based on user profiles. */ public abstract class AbstractUserComparator implements Comparator { - private HashMap mUserSerialCache = new HashMap<>(); private final UserManagerCompat mUserManager; private final UserHandleCompat mMyUser; @@ -43,25 +41,9 @@ public abstract class AbstractUserComparator implements Comp if (mMyUser.equals(lhs.user)) { return -1; } else { - Long aUserSerial = getAndCacheUserSerial(lhs.user); - Long bUserSerial = getAndCacheUserSerial(rhs.user); + Long aUserSerial = mUserManager.getSerialNumberForUser(lhs.user); + Long bUserSerial = mUserManager.getSerialNumberForUser(rhs.user); return aUserSerial.compareTo(bUserSerial); } } - - /** - * Returns the user serial for this user, using a cached serial if possible. - */ - private Long getAndCacheUserSerial(UserHandleCompat user) { - Long userSerial = mUserSerialCache.get(user); - if (userSerial == null) { - userSerial = mUserManager.getSerialNumberForUser(user); - mUserSerialCache.put(user, userSerial); - } - return userSerial; - } - - public void clearUserCache() { - mUserSerialCache.clear(); - } } diff --git a/src/com/android/launcher3/model/AppNameComparator.java b/src/com/android/launcher3/model/AppNameComparator.java index c4b74d4dc..5f80037dc 100644 --- a/src/com/android/launcher3/model/AppNameComparator.java +++ b/src/com/android/launcher3/model/AppNameComparator.java @@ -68,8 +68,6 @@ public class AppNameComparator { * Returns a locale-aware comparator that will alphabetically order a list of applications. */ public Comparator getAppInfoComparator() { - // Clear the user serial cache so that we get serials as needed in the comparator - mAppInfoComparator.clearUserCache(); return mAppInfoComparator; } -- cgit v1.2.3 From c679ed623324954069446f50e9c4ace359fa55e7 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 4 Aug 2015 15:09:58 -0700 Subject: Removing account manager calls Change-Id: Ic88139f6ef34046eb3b551d8a75d5f97e1fe3d52 --- AndroidManifest.xml | 1 - src/com/android/launcher3/LauncherClings.java | 11 +---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 1fb8e8d01..3af38f384 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -53,7 +53,6 @@ - diff --git a/src/com/android/launcher3/LauncherClings.java b/src/com/android/launcher3/LauncherClings.java index c13752cb1..c44ea6bcd 100644 --- a/src/com/android/launcher3/LauncherClings.java +++ b/src/com/android/launcher3/LauncherClings.java @@ -44,8 +44,6 @@ class LauncherClings implements OnClickListener { private static final String TAG_CROP_TOP_AND_SIDES = "crop_bg_top_and_sides"; - private static final boolean DISABLE_CLINGS = false; - private static final int SHOW_CLING_DURATION = 250; private static final int DISMISS_CLING_DURATION = 200; @@ -215,10 +213,6 @@ class LauncherClings implements OnClickListener { /** Returns whether the clings are enabled or should be shown */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) private boolean areClingsEnabled() { - if (DISABLE_CLINGS) { - return false; - } - // disable clings when running in a test harness if(ActivityManager.isRunningInTestHarness()) return false; @@ -231,10 +225,7 @@ class LauncherClings implements OnClickListener { // Restricted secondary users (child mode) will potentially have very few apps // seeded when they start up for the first time. Clings won't work well with that - boolean supportsLimitedUsers = - android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; - Account[] accounts = AccountManager.get(mLauncher).getAccounts(); - if (supportsLimitedUsers && accounts.length == 0) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { UserManager um = (UserManager) mLauncher.getSystemService(Context.USER_SERVICE); Bundle restrictions = um.getUserRestrictions(); if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { -- cgit v1.2.3 From fb0f1095390d19d2cd6be127eb1aa3a83259b012 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 4 Aug 2015 16:02:52 -0700 Subject: Updating the default layouts for launcher3 Change-Id: I088c7195ae1985788e845900463d22973a0f61d4 --- res/xml/default_workspace_4x4.xml | 101 ++++++-------------------------------- res/xml/default_workspace_5x5.xml | 100 ++++++------------------------------- res/xml/default_workspace_5x6.xml | 100 +++++-------------------------------- res/xml/dw_phone_hotseat.xml | 63 ++++++++++++++++++++++++ res/xml/dw_tablet_hotseat.xml | 78 +++++++++++++++++++++++++++++ 5 files changed, 184 insertions(+), 258 deletions(-) create mode 100644 res/xml/dw_phone_hotseat.xml create mode 100644 res/xml/dw_tablet_hotseat.xml diff --git a/res/xml/default_workspace_4x4.xml b/res/xml/default_workspace_4x4.xml index 9bec86aa8..060a1f880 100644 --- a/res/xml/default_workspace_4x4.xml +++ b/res/xml/default_workspace_4x4.xml @@ -15,102 +15,33 @@ --> - - - - - - - + + - - - - - - - - + - - - - - + launcher:y="3" > + + - + launcher:y="3" > + + + - - - - - - - - - - - - - + launcher:y="3" > + + diff --git a/res/xml/default_workspace_5x5.xml b/res/xml/default_workspace_5x5.xml index 9bec86aa8..322661720 100644 --- a/res/xml/default_workspace_5x5.xml +++ b/res/xml/default_workspace_5x5.xml @@ -15,102 +15,34 @@ --> - - - - - - - + + - - - - - - - - + - - - + launcher:y="4" > + + - - - - - - - - + launcher:screen="0" + launcher:x="1" + launcher:y="4" > + + - + - - - - + launcher:y="4" > + + - diff --git a/res/xml/default_workspace_5x6.xml b/res/xml/default_workspace_5x6.xml index d42a93a6a..bc236fb14 100644 --- a/res/xml/default_workspace_5x6.xml +++ b/res/xml/default_workspace_5x6.xml @@ -15,101 +15,23 @@ --> - - - + + - - + - - - - - - - - - - - - - - - - - - - - - - - - - + launcher:y="4" + launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_CONTACTS;end" /> - - - - - - + launcher:y="4" > + + + diff --git a/res/xml/dw_phone_hotseat.xml b/res/xml/dw_phone_hotseat.xml new file mode 100644 index 000000000..b58994d1d --- /dev/null +++ b/res/xml/dw_phone_hotseat.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/xml/dw_tablet_hotseat.xml b/res/xml/dw_tablet_hotseat.xml new file mode 100644 index 000000000..671ccba3c --- /dev/null +++ b/res/xml/dw_tablet_hotseat.xml @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From 006ee269ba2e9946a83b42f96d4a0296254cba4a Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 3 Aug 2015 14:40:11 -0700 Subject: Refactoring search bar animations. - This refactoring ensures that LauncherStateTransition does not do its own animation on the QSB, and that all animations to the SearchDropTargetBar go through its own animators. Bug: 22515084 Change-Id: Ia7d13c44d861eac7517076b52a9651a90911ed0a --- src/com/android/launcher3/DeviceProfile.java | 3 +- src/com/android/launcher3/DragLayer.java | 4 +- src/com/android/launcher3/Folder.java | 2 +- src/com/android/launcher3/Launcher.java | 48 ++--- .../LauncherStateTransitionAnimation.java | 214 ++++++++++++--------- .../launcher3/LauncherViewPropertyAnimator.java | 4 +- src/com/android/launcher3/SearchDropTargetBar.java | 209 ++++++++++---------- src/com/android/launcher3/Workspace.java | 25 ++- .../WorkspaceStateTransitionAnimation.java | 77 +------- 9 files changed, 283 insertions(+), 303 deletions(-) diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 6e90fc291..774594fe2 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -25,7 +25,6 @@ import android.graphics.Paint.FontMetrics; import android.graphics.Point; import android.graphics.Rect; import android.util.DisplayMetrics; -import android.util.Size; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; @@ -385,7 +384,7 @@ public class DeviceProfile { final boolean isLayoutRtl = Utilities.isRtl(launcher.getResources()); // Layout the search bar space - View searchBar = launcher.getSearchBar(); + View searchBar = launcher.getSearchDropTargetBar(); lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams(); if (hasVerticalBarLayout) { // Vertical search bar space -- The search bar is fixed in the layout to be on the left diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java index aaa14e6a6..1c18747c1 100644 --- a/src/com/android/launcher3/DragLayer.java +++ b/src/com/android/launcher3/DragLayer.java @@ -159,7 +159,7 @@ public class DragLayer extends InsettableFrameLayout { } private boolean isEventOverDropTargetBar(MotionEvent ev) { - getDescendantRectRelativeToSelf(mLauncher.getSearchBar(), mHitRect); + getDescendantRectRelativeToSelf(mLauncher.getSearchDropTargetBar(), mHitRect); if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) { return true; } @@ -321,7 +321,7 @@ public class DragLayer extends InsettableFrameLayout { childrenForAccessibility.add(currentFolder); if (isInAccessibleDrag()) { - childrenForAccessibility.add(mLauncher.getSearchBar()); + childrenForAccessibility.add(mLauncher.getSearchDropTargetBar()); } } else { super.addChildrenForAccessibility(childrenForAccessibility); diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java index 2e19f6eba..535d1a443 100644 --- a/src/com/android/launcher3/Folder.java +++ b/src/com/android/launcher3/Folder.java @@ -275,7 +275,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList @Override public void enableAccessibleDrag(boolean enable) { - mLauncher.getSearchBar().enableAccessibleDrag(enable); + mLauncher.getSearchDropTargetBar().enableAccessibleDrag(enable); for (int i = 0; i < mContent.getChildCount(); i++) { mContent.getPageAt(i).enableAccessibleDrag(enable, CellLayout.FOLDER_ACCESSIBILITY_DRAG); } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 15e43b2b9..aee044097 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -132,8 +132,7 @@ import java.util.concurrent.atomic.AtomicInteger; */ public class Launcher extends Activity implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, - View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener, - LauncherStateTransitionAnimation.Callbacks { + View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener { static final String TAG = "Launcher"; static final boolean LOGD = false; @@ -452,7 +451,7 @@ public class Launcher extends Activity mDragController = new DragController(this); mInflater = getLayoutInflater(); - mStateTransitionAnimation = new LauncherStateTransitionAnimation(this, this); + mStateTransitionAnimation = new LauncherStateTransitionAnimation(this); mStats = new Stats(this); @@ -1844,7 +1843,7 @@ public class Launcher extends Activity return mOverviewPanel; } - public SearchDropTargetBar getSearchBar() { + public SearchDropTargetBar getSearchDropTargetBar() { return mSearchDropTargetBar; } @@ -3265,14 +3264,6 @@ public class Launcher extends Activity } } - @Override - public void onStateTransitionHideSearchBar() { - // Hide the search bar - if (mSearchDropTargetBar != null) { - mSearchDropTargetBar.hideSearchBar(false /* animated */); - } - } - public void showWorkspace(boolean animated) { showWorkspace(WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, animated, null); } @@ -3290,16 +3281,9 @@ public class Launcher extends Activity boolean changed = mState != State.WORKSPACE || mWorkspace.getState() != Workspace.State.NORMAL; if (changed) { - boolean wasInSpringLoadedMode = (mState != State.WORKSPACE); mWorkspace.setVisibility(View.VISIBLE); - mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.NORMAL, - snapToPage, animated, onCompleteRunnable); - - // Show the search bar (only animate if we were showing the drop target bar in spring - // loaded mode) - if (mSearchDropTargetBar != null) { - mSearchDropTargetBar.showSearchBar(animated && wasInSpringLoadedMode); - } + mStateTransitionAnimation.startAnimationToWorkspace(mState, mWorkspace.getState(), + Workspace.State.NORMAL, snapToPage, animated, onCompleteRunnable); // Set focus to the AppsCustomize button if (mAllAppsButton != null) { @@ -3323,7 +3307,8 @@ public class Launcher extends Activity void showOverviewMode(boolean animated) { mWorkspace.setVisibility(View.VISIBLE); - mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.OVERVIEW, + mStateTransitionAnimation.startAnimationToWorkspace(mState, mWorkspace.getState(), + Workspace.State.OVERVIEW, WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, animated, null /* onCompleteRunnable */); mState = State.WORKSPACE; @@ -3378,9 +3363,10 @@ public class Launcher extends Activity } if (toState == State.APPS) { - mStateTransitionAnimation.startAnimationToAllApps(animated, focusSearchBar); + mStateTransitionAnimation.startAnimationToAllApps(mWorkspace.getState(), animated, + focusSearchBar); } else { - mStateTransitionAnimation.startAnimationToWidgets(animated); + mStateTransitionAnimation.startAnimationToWidgets(mWorkspace.getState(), animated); } // Change the state *after* we've called all the transition code @@ -3402,10 +3388,9 @@ public class Launcher extends Activity * new state. */ public Animator startWorkspaceStateChangeAnimation(Workspace.State toState, int toPage, - boolean animated, boolean hasOverlaySearchBar, HashMap layerViews) { + boolean animated, HashMap layerViews) { Workspace.State fromState = mWorkspace.getState(); - Animator anim = mWorkspace.setStateWithAnimation(toState, toPage, animated, - hasOverlaySearchBar, layerViews); + Animator anim = mWorkspace.setStateWithAnimation(toState, toPage, animated, layerViews); updateInteraction(fromState, toState); return anim; } @@ -3417,7 +3402,8 @@ public class Launcher extends Activity return; } - mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.SPRING_LOADED, + mStateTransitionAnimation.startAnimationToWorkspace(mState, mWorkspace.getState(), + Workspace.State.SPRING_LOADED, WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, true /* animated */, null /* onCompleteRunnable */); mState = isAppsViewVisible() ? State.APPS_SPRING_LOADED : State.WIDGETS_SPRING_LOADED; @@ -4517,14 +4503,16 @@ public class Launcher extends Activity if (mWorkspace != null) mWorkspace.setAlpha(1f); if (mHotseat != null) mHotseat.setAlpha(1f); if (mPageIndicators != null) mPageIndicators.setAlpha(1f); - if (mSearchDropTargetBar != null) mSearchDropTargetBar.showSearchBar(false); + if (mSearchDropTargetBar != null) mSearchDropTargetBar.animateToState( + SearchDropTargetBar.State.SEARCH_BAR, 0); } void hideWorkspaceSearchAndHotseat() { if (mWorkspace != null) mWorkspace.setAlpha(0f); if (mHotseat != null) mHotseat.setAlpha(0f); if (mPageIndicators != null) mPageIndicators.setAlpha(0f); - if (mSearchDropTargetBar != null) mSearchDropTargetBar.hideSearchBar(false); + if (mSearchDropTargetBar != null) mSearchDropTargetBar.animateToState( + SearchDropTargetBar.State.INVISIBLE, 0); } // TODO: These method should be a part of LauncherSearchCallback diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java index d69b7432d..acace8299 100644 --- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java +++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java @@ -79,13 +79,6 @@ import java.util.HashMap; */ public class LauncherStateTransitionAnimation { - /** - * Callbacks made during the state transition - */ - interface Callbacks { - public void onStateTransitionHideSearchBar(); - } - /** * Private callbacks made during transition setup. */ @@ -111,12 +104,10 @@ public class LauncherStateTransitionAnimation { public static final int SINGLE_FRAME_DELAY = 16; @Thunk Launcher mLauncher; - @Thunk Callbacks mCb; - @Thunk AnimatorSet mStateAnimation; + @Thunk AnimatorSet mCurrentAnimation; - public LauncherStateTransitionAnimation(Launcher l, Callbacks cb) { + public LauncherStateTransitionAnimation(Launcher l) { mLauncher = l; - mCb = cb; } /** @@ -125,8 +116,8 @@ public class LauncherStateTransitionAnimation { * @param startSearchAfterTransition Immediately starts app search after the transition to * All Apps is completed. */ - public void startAnimationToAllApps(final boolean animated, - final boolean startSearchAfterTransition) { + public void startAnimationToAllApps(final Workspace.State fromWorkspaceState, + final boolean animated, final boolean startSearchAfterTransition) { final AllAppsContainerView toView = mLauncher.getAppsView(); final View buttonView = mLauncher.getAllAppsButton(); PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() { @@ -159,15 +150,16 @@ public class LauncherStateTransitionAnimation { } }; // Only animate the search bar if animating from spring loaded mode back to all apps - startAnimationToOverlay(Workspace.State.NORMAL_HIDDEN, buttonView, toView, - toView.getContentView(), toView.getRevealView(), toView.getSearchBarView(), - animated, true /* hideSearchBar */, cb); + mCurrentAnimation = startAnimationToOverlay(fromWorkspaceState, + Workspace.State.NORMAL_HIDDEN, buttonView, toView, toView.getContentView(), + toView.getRevealView(), toView.getSearchBarView(), animated, cb); } /** * Starts an animation to the widgets view. */ - public void startAnimationToWidgets(final boolean animated) { + public void startAnimationToWidgets(final Workspace.State fromWorkspaceState, + final boolean animated) { final WidgetsContainerView toView = mLauncher.getWidgetsView(); final View buttonView = mLauncher.getWidgetsButton(); @@ -177,17 +169,17 @@ public class LauncherStateTransitionAnimation { return 0.3f; } }; - startAnimationToOverlay(Workspace.State.OVERVIEW_HIDDEN, buttonView, toView, - toView.getContentView(), toView.getRevealView(), null, animated, - true /* hideSearchBar */, cb); + mCurrentAnimation = startAnimationToOverlay(fromWorkspaceState, + Workspace.State.OVERVIEW_HIDDEN, buttonView, toView, toView.getContentView(), + toView.getRevealView(), null, animated, cb); } /** * Starts and animation to the workspace from the current overlay view. */ public void startAnimationToWorkspace(final Launcher.State fromState, - final Workspace.State toWorkspaceState, final int toWorkspacePage, - final boolean animated, final Runnable onCompleteRunnable) { + final Workspace.State fromWorkspaceState, final Workspace.State toWorkspaceState, + final int toWorkspacePage, final boolean animated, final Runnable onCompleteRunnable) { if (toWorkspaceState != Workspace.State.NORMAL && toWorkspaceState != Workspace.State.SPRING_LOADED && toWorkspaceState != Workspace.State.OVERVIEW) { @@ -195,10 +187,10 @@ public class LauncherStateTransitionAnimation { } if (fromState == Launcher.State.APPS || fromState == Launcher.State.APPS_SPRING_LOADED) { - startAnimationToWorkspaceFromAllApps(toWorkspaceState, toWorkspacePage, + startAnimationToWorkspaceFromAllApps(fromWorkspaceState, toWorkspaceState, toWorkspacePage, animated, onCompleteRunnable); } else { - startAnimationToWorkspaceFromWidgets(toWorkspaceState, toWorkspacePage, + startAnimationToWorkspaceFromWidgets(fromWorkspaceState, toWorkspaceState, toWorkspacePage, animated, onCompleteRunnable); } } @@ -207,10 +199,11 @@ public class LauncherStateTransitionAnimation { * Creates and starts a new animation to a particular overlay view. */ @SuppressLint("NewApi") - private void startAnimationToOverlay(final Workspace.State toWorkspaceState, - final View buttonView, final View toView, final View contentView, final View revealView, - final View overlaySearchBarView, final boolean animated, final boolean hideSearchBar, - final PrivateTransitionCallbacks pCb) { + private AnimatorSet startAnimationToOverlay(final Workspace.State fromWorkspaceState, + final Workspace.State toWorkspaceState, final View buttonView, final View toView, + final View contentView, final View revealView, final View overlaySearchBarView, + final boolean animated, final PrivateTransitionCallbacks pCb) { + final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet(); final Resources res = mLauncher.getResources(); final boolean material = Utilities.isLmpOrAbove(); final int revealDuration = res.getInteger(R.integer.config_overlayRevealTime); @@ -230,11 +223,13 @@ public class LauncherStateTransitionAnimation { // Create the workspace animation. // NOTE: this call apparently also sets the state for the workspace if !animated Animator workspaceAnim = mLauncher.startWorkspaceStateChangeAnimation(toWorkspaceState, -1, - animated, overlaySearchBarView != null /* hasOverlaySearchBar */, layerViews); + animated, layerViews); - if (animated && initialized) { - mStateAnimation = LauncherAnimUtils.createAnimatorSet(); + // Animate the search bar + startWorkspaceSearchBarAnimation(animation, fromWorkspaceState, toWorkspaceState, + animated ? revealDuration : 0, overlaySearchBarView); + if (animated && initialized) { // Setup the reveal view animation int width = revealView.getMeasuredWidth(); int height = revealView.getMeasuredHeight(); @@ -274,7 +269,7 @@ public class LauncherStateTransitionAnimation { // Play the animation layerViews.put(revealView, BUILD_AND_SET_LAYER); - mStateAnimation.play(panelAlphaAndDrift); + animation.play(panelAlphaAndDrift); if (overlaySearchBarView != null) { overlaySearchBarView.setAlpha(0f); @@ -282,7 +277,7 @@ public class LauncherStateTransitionAnimation { searchBarAlpha.setDuration(100); searchBarAlpha.setInterpolator(new AccelerateInterpolator(1.5f)); layerViews.put(overlaySearchBarView, BUILD_AND_SET_LAYER); - mStateAnimation.play(searchBarAlpha); + animation.play(searchBarAlpha); } // Setup the animation for the content view @@ -297,13 +292,13 @@ public class LauncherStateTransitionAnimation { pageDrift.setDuration(revealDuration); pageDrift.setInterpolator(new LogDecelerateInterpolator(100, 0)); pageDrift.setStartDelay(itemsAlphaStagger); - mStateAnimation.play(pageDrift); + animation.play(pageDrift); ObjectAnimator itemsAlpha = ObjectAnimator.ofFloat(contentView, "alpha", 0f, 1f); itemsAlpha.setDuration(revealDuration); itemsAlpha.setInterpolator(new AccelerateInterpolator(1.5f)); itemsAlpha.setStartDelay(itemsAlphaStagger); - mStateAnimation.play(itemsAlpha); + animation.play(itemsAlpha); if (material) { float startRadius = pCb.getMaterialRevealViewStartFinalRadius(); @@ -316,10 +311,10 @@ public class LauncherStateTransitionAnimation { if (listener != null) { reveal.addListener(listener); } - mStateAnimation.play(reveal); + animation.play(reveal); } - mStateAnimation.addListener(new AnimatorListenerAdapter() { + animation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { dispatchOnLauncherTransitionEnd(fromView, animated, false); @@ -335,12 +330,8 @@ public class LauncherStateTransitionAnimation { } } - if (hideSearchBar) { - mCb.onStateTransitionHideSearchBar(); - } - // This can hold unnecessary references to views. - mStateAnimation = null; + cleanupAnimation(); pCb.onTransitionComplete(); } @@ -348,7 +339,7 @@ public class LauncherStateTransitionAnimation { // Play the workspace animation if (workspaceAnim != null) { - mStateAnimation.play(workspaceAnim); + animation.play(workspaceAnim); } // Dispatch the prepare transition signal @@ -356,12 +347,12 @@ public class LauncherStateTransitionAnimation { dispatchOnLauncherTransitionPrepare(toView, animated, false); - final AnimatorSet stateAnimation = mStateAnimation; + final AnimatorSet stateAnimation = animation; final Runnable startAnimRunnable = new Runnable() { public void run() { - // Check that mStateAnimation hasn't changed while + // Check that mCurrentAnimation hasn't changed while // we waited for a layout/draw pass - if (mStateAnimation != stateAnimation) + if (mCurrentAnimation != stateAnimation) return; dispatchOnLauncherTransitionStart(fromView, animated, false); dispatchOnLauncherTransitionStart(toView, animated, false); @@ -380,12 +371,14 @@ public class LauncherStateTransitionAnimation { // Focus the new view toView.requestFocus(); - mStateAnimation.start(); + stateAnimation.start(); } }; toView.bringToFront(); toView.setVisibility(View.VISIBLE); toView.post(startAnimRunnable); + + return animation; } else { toView.setTranslationX(0.0f); toView.setTranslationY(0.0f); @@ -397,10 +390,6 @@ public class LauncherStateTransitionAnimation { // Show the content view contentView.setVisibility(View.VISIBLE); - if (hideSearchBar) { - mCb.onStateTransitionHideSearchBar(); - } - dispatchOnLauncherTransitionPrepare(fromView, animated, false); dispatchOnLauncherTransitionStart(fromView, animated, false); dispatchOnLauncherTransitionEnd(fromView, animated, false); @@ -408,18 +397,19 @@ public class LauncherStateTransitionAnimation { dispatchOnLauncherTransitionStart(toView, animated, false); dispatchOnLauncherTransitionEnd(toView, animated, false); pCb.onTransitionComplete(); + + return null; } } /** * Starts and animation to the workspace from the apps view. */ - private void startAnimationToWorkspaceFromAllApps(final Workspace.State toWorkspaceState, - final int toWorkspacePage, final boolean animated, final Runnable onCompleteRunnable) { + private void startAnimationToWorkspaceFromAllApps(final Workspace.State fromWorkspaceState, + final Workspace.State toWorkspaceState, final int toWorkspacePage, + final boolean animated, final Runnable onCompleteRunnable) { AllAppsContainerView appsView = mLauncher.getAppsView(); PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() { - int[] mAllAppsToPanelDelta; - @Override float getMaterialRevealViewFinalAlpha(View revealView) { // No alpha anim from all apps @@ -451,8 +441,8 @@ public class LauncherStateTransitionAnimation { } }; // Only animate the search bar if animating to spring loaded mode from all apps - startAnimationToWorkspaceFromOverlay(toWorkspaceState, toWorkspacePage, - mLauncher.getAllAppsButton(), appsView, appsView.getContentView(), + mCurrentAnimation = startAnimationToWorkspaceFromOverlay(fromWorkspaceState, toWorkspaceState, + toWorkspacePage, mLauncher.getAllAppsButton(), appsView, appsView.getContentView(), appsView.getRevealView(), appsView.getSearchBarView(), animated, onCompleteRunnable, cb); } @@ -460,8 +450,9 @@ public class LauncherStateTransitionAnimation { /** * Starts and animation to the workspace from the widgets view. */ - private void startAnimationToWorkspaceFromWidgets(final Workspace.State toWorkspaceState, - final int toWorkspacePage, final boolean animated, final Runnable onCompleteRunnable) { + private void startAnimationToWorkspaceFromWidgets(final Workspace.State fromWorkspaceState, + final Workspace.State toWorkspaceState, final int toWorkspacePage, + final boolean animated, final Runnable onCompleteRunnable) { final WidgetsContainerView widgetsView = mLauncher.getWidgetsView(); PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() { @Override @@ -479,19 +470,21 @@ public class LauncherStateTransitionAnimation { }; } }; - startAnimationToWorkspaceFromOverlay(toWorkspaceState, toWorkspacePage, - mLauncher.getWidgetsButton(), widgetsView, widgetsView.getContentView(), - widgetsView.getRevealView(), null, animated, onCompleteRunnable, cb); + mCurrentAnimation = startAnimationToWorkspaceFromOverlay(fromWorkspaceState, + toWorkspaceState, toWorkspacePage, mLauncher.getWidgetsButton(), widgetsView, + widgetsView.getContentView(), widgetsView.getRevealView(), null, animated, + onCompleteRunnable, cb); } /** * Creates and starts a new animation to the workspace. */ - private void startAnimationToWorkspaceFromOverlay(final Workspace.State toWorkspaceState, - final int toWorkspacePage, final View buttonView, final View fromView, - final View contentView, final View revealView, final View overlaySearchBarView, - final boolean animated, final Runnable onCompleteRunnable, - final PrivateTransitionCallbacks pCb) { + private AnimatorSet startAnimationToWorkspaceFromOverlay(final Workspace.State fromWorkspaceState, + final Workspace.State toWorkspaceState, final int toWorkspacePage, final View buttonView, + final View fromView, final View contentView, final View revealView, + final View overlaySearchBarView, final boolean animated, final Runnable onCompleteRunnable, + final PrivateTransitionCallbacks pCb) { + final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet(); final Resources res = mLauncher.getResources(); final boolean material = Utilities.isLmpOrAbove(); final int revealDuration = res.getInteger(R.integer.config_overlayRevealTime); @@ -511,15 +504,16 @@ public class LauncherStateTransitionAnimation { // Create the workspace animation. // NOTE: this call apparently also sets the state for the workspace if !animated Animator workspaceAnim = mLauncher.startWorkspaceStateChangeAnimation(toWorkspaceState, - toWorkspacePage, animated, overlaySearchBarView != null /* hasOverlaySearchBar */, - layerViews); + toWorkspacePage, animated, layerViews); - if (animated && initialized) { - mStateAnimation = LauncherAnimUtils.createAnimatorSet(); + // Animate the search bar + startWorkspaceSearchBarAnimation(animation, fromWorkspaceState, toWorkspaceState, + animated ? revealDuration : 0, overlaySearchBarView); + if (animated && initialized) { // Play the workspace animation if (workspaceAnim != null) { - mStateAnimation.play(workspaceAnim); + animation.play(workspaceAnim); } // hideAppsCustomizeHelper is called in some cases when it is already hidden @@ -558,14 +552,14 @@ public class LauncherStateTransitionAnimation { panelDriftY.setDuration(revealDuration - SINGLE_FRAME_DELAY); panelDriftY.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY); panelDriftY.setInterpolator(decelerateInterpolator); - mStateAnimation.play(panelDriftY); + animation.play(panelDriftY); ObjectAnimator panelDriftX = ObjectAnimator.ofFloat(revealView, "translationX", 0, revealViewToXDrift); panelDriftX.setDuration(revealDuration - SINGLE_FRAME_DELAY); panelDriftX.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY); panelDriftX.setInterpolator(decelerateInterpolator); - mStateAnimation.play(panelDriftX); + animation.play(panelDriftX); // Setup animation for the reveal panel alpha final float revealViewToAlpha = !material ? 0f : @@ -576,7 +570,7 @@ public class LauncherStateTransitionAnimation { panelAlpha.setDuration(material ? revealDuration : 150); panelAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY); panelAlpha.setInterpolator(decelerateInterpolator); - mStateAnimation.play(panelAlpha); + animation.play(panelAlpha); } // Setup the animation for the content view @@ -589,13 +583,13 @@ public class LauncherStateTransitionAnimation { pageDrift.setDuration(revealDuration - SINGLE_FRAME_DELAY); pageDrift.setInterpolator(decelerateInterpolator); pageDrift.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY); - mStateAnimation.play(pageDrift); + animation.play(pageDrift); contentView.setAlpha(1f); ObjectAnimator itemsAlpha = ObjectAnimator.ofFloat(contentView, "alpha", 1f, 0f); itemsAlpha.setDuration(100); itemsAlpha.setInterpolator(decelerateInterpolator); - mStateAnimation.play(itemsAlpha); + animation.play(itemsAlpha); if (overlaySearchBarView != null) { overlaySearchBarView.setAlpha(1f); @@ -604,7 +598,7 @@ public class LauncherStateTransitionAnimation { searchAlpha.setInterpolator(decelerateInterpolator); searchAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY); layerViews.put(overlaySearchBarView, BUILD_AND_SET_LAYER); - mStateAnimation.play(searchAlpha); + animation.play(searchAlpha); } if (material) { @@ -620,14 +614,14 @@ public class LauncherStateTransitionAnimation { if (listener != null) { reveal.addListener(listener); } - mStateAnimation.play(reveal); + animation.play(reveal); } dispatchOnLauncherTransitionPrepare(fromView, animated, true); dispatchOnLauncherTransitionPrepare(toView, animated, true); } - mStateAnimation.addListener(new AnimatorListenerAdapter() { + animation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { fromView.setVisibility(View.GONE); @@ -657,18 +651,19 @@ public class LauncherStateTransitionAnimation { } // This can hold unnecessary references to views. - mStateAnimation = null; + cleanupAnimation(); pCb.onTransitionComplete(); } }); - final AnimatorSet stateAnimation = mStateAnimation; + final AnimatorSet stateAnimation = animation; final Runnable startAnimRunnable = new Runnable() { public void run() { - // Check that mStateAnimation hasn't changed while + // Check that mCurrentAnimation hasn't changed while // we waited for a layout/draw pass - if (mStateAnimation != stateAnimation) + if (mCurrentAnimation != stateAnimation) return; + dispatchOnLauncherTransitionStart(fromView, animated, false); dispatchOnLauncherTransitionStart(toView, animated, false); @@ -682,10 +677,12 @@ public class LauncherStateTransitionAnimation { v.buildLayer(); } } - mStateAnimation.start(); + stateAnimation.start(); } }; fromView.post(startAnimRunnable); + + return animation; } else { fromView.setVisibility(View.GONE); dispatchOnLauncherTransitionPrepare(fromView, animated, true); @@ -700,9 +697,44 @@ public class LauncherStateTransitionAnimation { if (onCompleteRunnable != null) { onCompleteRunnable.run(); } + + return null; } } + /** + * Coordinates the workspace search bar animation along with the launcher state animation. + */ + private void startWorkspaceSearchBarAnimation(AnimatorSet animation, + final Workspace.State fromWorkspaceState, final Workspace.State toWorkspaceState, int duration, + View overlaySearchBar) { + final SearchDropTargetBar.State toSearchBarState = + toWorkspaceState.getSearchDropTargetBarState(); + + if (overlaySearchBar != null) { + if ((toWorkspaceState == Workspace.State.NORMAL) && + (fromWorkspaceState == Workspace.State.NORMAL_HIDDEN)) { + // If we are transitioning from the overlay to the workspace, then show the + // workspace search bar immediately and let the overlay search bar fade out on top + mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, 0); + } else if (fromWorkspaceState == Workspace.State.NORMAL) { + // If we are transitioning from the workspace to the overlay, then keep the + // workspace search bar visible until the overlay search bar fades in on top + animation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, 0); + } + }); + } else { + // Otherwise, then just animate the workspace search bar normally + mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, duration); + } + } else { + // If there is no overlay search bar, then just animate the workspace search bar + mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, duration); + } + } /** * Dispatches the prepare-transition event to suitable views. @@ -753,10 +785,14 @@ public class LauncherStateTransitionAnimation { * Cancels the current animation. */ private void cancelAnimation() { - if (mStateAnimation != null) { - mStateAnimation.setDuration(0); - mStateAnimation.cancel(); - mStateAnimation = null; + if (mCurrentAnimation != null) { + mCurrentAnimation.setDuration(0); + mCurrentAnimation.cancel(); + mCurrentAnimation = null; } } + + private void cleanupAnimation() { + mCurrentAnimation = null; + } } diff --git a/src/com/android/launcher3/LauncherViewPropertyAnimator.java b/src/com/android/launcher3/LauncherViewPropertyAnimator.java index 4cafbbfa6..4406a2c5c 100644 --- a/src/com/android/launcher3/LauncherViewPropertyAnimator.java +++ b/src/com/android/launcher3/LauncherViewPropertyAnimator.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.EnumSet; public class LauncherViewPropertyAnimator extends Animator implements AnimatorListener { + enum Properties { TRANSLATION_X, TRANSLATION_Y, @@ -51,13 +52,12 @@ public class LauncherViewPropertyAnimator extends Animator implements AnimatorLi long mStartDelay; long mDuration; TimeInterpolator mInterpolator; - ArrayList mListeners; + ArrayList mListeners = new ArrayList<>(); boolean mRunning = false; FirstFrameAnimatorHelper mFirstFrameHelper; public LauncherViewPropertyAnimator(View target) { mTarget = target; - mListeners = new ArrayList(); } @Override diff --git a/src/com/android/launcher3/SearchDropTargetBar.java b/src/com/android/launcher3/SearchDropTargetBar.java index 4cdf1cac9..fe89c15a7 100644 --- a/src/com/android/launcher3/SearchDropTargetBar.java +++ b/src/com/android/launcher3/SearchDropTargetBar.java @@ -18,12 +18,11 @@ package com.android.launcher3; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; +import android.view.accessibility.AccessibilityManager; import android.view.animation.AccelerateInterpolator; import android.widget.FrameLayout; @@ -33,17 +32,41 @@ import android.widget.FrameLayout; */ public class SearchDropTargetBar extends FrameLayout implements DragController.DragListener { - private static final int TRANSITION_DURATION = 200; + /** The different states that the search bar space can be in. */ + public enum State { + INVISIBLE (0f, 0f), + SEARCH_BAR (1f, 0f), + DROP_TARGET (0f, 1f); - private ObjectAnimator mShowDropTargetBarAnim; - private ValueAnimator mHideSearchBarAnim; + private final float mSearchBarAlpha; + private final float mDropTargetBarAlpha; + + State(float sbAlpha, float dtbAlpha) { + mSearchBarAlpha = sbAlpha; + mDropTargetBarAlpha = dtbAlpha; + } + + float getSearchBarAlpha() { + return mSearchBarAlpha; + } + + float getDropTargetBarAlpha() { + return mDropTargetBarAlpha; + } + } + + private static int DEFAULT_DRAG_FADE_DURATION = 175; + + private LauncherViewPropertyAnimator mDropTargetBarAnimator; + private LauncherViewPropertyAnimator mQSBSearchBarAnimator; private static final AccelerateInterpolator sAccelerateInterpolator = new AccelerateInterpolator(); - private boolean mIsSearchBarHidden; - private View mQSBSearchBar; + private State mState = State.SEARCH_BAR; + private View mQSB; private View mDropTargetBar; private boolean mDeferOnDragEnd = false; + private boolean mAccessibilityEnabled = false; // Drop targets private ButtonDropTarget mInfoDropTarget; @@ -75,39 +98,6 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D mUninstallDropTarget.setLauncher(launcher); } - public void setQsbSearchBar(View qsb) { - mQSBSearchBar = qsb; - if (mQSBSearchBar != null) { - mHideSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "alpha", 1f, 0f); - setupAnimation(mHideSearchBarAnim, mQSBSearchBar); - } else { - // Create a no-op animation of the search bar is null - mHideSearchBarAnim = ValueAnimator.ofFloat(0, 0); - mHideSearchBarAnim.setDuration(TRANSITION_DURATION); - } - } - - private void prepareStartAnimation(View v) { - // Enable the hw layers before the animation starts (will be disabled in the onAnimationEnd - // callback below) - if (v != null) { - v.setLayerType(View.LAYER_TYPE_HARDWARE, null); - } - } - - private void setupAnimation(ValueAnimator anim, final View v) { - anim.setInterpolator(sAccelerateInterpolator); - anim.setDuration(TRANSITION_DURATION); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (v != null) { - v.setLayerType(View.LAYER_TYPE_NONE, null); - } - } - }); - } - @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -124,72 +114,84 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D // Create the various fade animations mDropTargetBar.setAlpha(0f); - mShowDropTargetBarAnim = LauncherAnimUtils.ofFloat(mDropTargetBar, "alpha", 0f, 1f); - setupAnimation(mShowDropTargetBarAnim, mDropTargetBar); - } - - /** - * Finishes all the animations on the search and drop target bars. - */ - public void finishAnimations() { - prepareStartAnimation(mDropTargetBar); - mShowDropTargetBarAnim.reverse(); - prepareStartAnimation(mQSBSearchBar); - mHideSearchBarAnim.reverse(); - } + mDropTargetBarAnimator = new LauncherViewPropertyAnimator(mDropTargetBar); + mDropTargetBarAnimator.setInterpolator(sAccelerateInterpolator); + mDropTargetBarAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + // Ensure that the view is visible for the animation + mDropTargetBar.setVisibility(View.VISIBLE); + } - /** - * Shows the search bar. - */ - public void showSearchBar(boolean animated) { - if (!mIsSearchBarHidden) return; - if (animated) { - prepareStartAnimation(mQSBSearchBar); - mHideSearchBarAnim.reverse(); - } else { - mHideSearchBarAnim.cancel(); - if (mQSBSearchBar != null) { - mQSBSearchBar.setAlpha(1f); + @Override + public void onAnimationEnd(Animator animation) { + if (mDropTargetBar != null) { + AlphaUpdateListener.updateVisibility(mDropTargetBar, mAccessibilityEnabled); + } } - } - mIsSearchBarHidden = false; + }); } - /** - * Hides the search bar. We only use this for clings. - */ - public void hideSearchBar(boolean animated) { - if (mIsSearchBarHidden) return; - if (animated) { - prepareStartAnimation(mQSBSearchBar); - mHideSearchBarAnim.start(); + public void setQsbSearchBar(View qsb) { + mQSB = qsb; + if (mQSB != null) { + // Update the search ber animation + mQSBSearchBarAnimator = new LauncherViewPropertyAnimator(mQSB); + mQSBSearchBarAnimator.setInterpolator(sAccelerateInterpolator); + mQSBSearchBarAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + // Ensure that the view is visible for the animation + if (mQSB != null) { + mQSB.setVisibility(View.VISIBLE); + } + } + + @Override + public void onAnimationEnd(Animator animation) { + if (mQSB != null) { + AlphaUpdateListener.updateVisibility(mQSB, mAccessibilityEnabled); + } + } + }); } else { - mHideSearchBarAnim.cancel(); - if (mQSBSearchBar != null) { - mQSBSearchBar.setAlpha(0f); - } + mQSBSearchBarAnimator = null; } - mIsSearchBarHidden = true; } /** - * Shows the drop target bar. + * Animates the current search bar state to a new state. If the {@param duration} is 0, then + * the state is applied immediately. */ - public void showDeleteTarget() { - // Animate out the QSB search bar, and animate in the drop target bar - prepareStartAnimation(mDropTargetBar); - mShowDropTargetBarAnim.start(); - hideSearchBar(true); + public void animateToState(State newState, int duration) { + if (mState != newState) { + mState = newState; + + // Update the accessibility state + AccessibilityManager am = (AccessibilityManager) + getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); + mAccessibilityEnabled = am.isEnabled(); + + animateViewAlpha(mQSBSearchBarAnimator, mQSB, newState.getSearchBarAlpha(), + duration); + animateViewAlpha(mDropTargetBarAnimator, mDropTargetBar, newState.getDropTargetBarAlpha(), + duration); + } } /** - * Hides the drop target bar. + * Convenience method to animate the alpha of a view using hardware layers. */ - public void hideDeleteTarget() { - // Restore the QSB search bar, and animate out the drop target bar - prepareStartAnimation(mDropTargetBar); - mShowDropTargetBarAnim.reverse(); - showSearchBar(true); + private void animateViewAlpha(LauncherViewPropertyAnimator animator, View v, float alpha, + int duration) { + if (v != null && Float.compare(v.getAlpha(), alpha) != 0) { + if (duration > 0) { + animator.alpha(alpha).withLayer().setDuration(duration).start(); + } else { + v.setAlpha(alpha); + AlphaUpdateListener.updateVisibility(v, mAccessibilityEnabled); + } + } } /* @@ -197,9 +199,13 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D */ @Override public void onDragStart(DragSource source, Object info, int dragAction) { - showDeleteTarget(); + animateToState(State.DROP_TARGET, DEFAULT_DRAG_FADE_DURATION); } + /** + * This is called to defer hiding the delete drop target until the drop animation has completed, + * instead of hiding immediately when the drag has ended. + */ public void deferOnDragEnd() { mDeferOnDragEnd = true; } @@ -207,22 +213,25 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D @Override public void onDragEnd() { if (!mDeferOnDragEnd) { - hideDeleteTarget(); + animateToState(State.SEARCH_BAR, DEFAULT_DRAG_FADE_DURATION); } else { mDeferOnDragEnd = false; } } + /** + * @return the bounds of the QSB search bar. + */ public Rect getSearchBarBounds() { - if (mQSBSearchBar != null) { + if (mQSB != null) { final int[] pos = new int[2]; - mQSBSearchBar.getLocationOnScreen(pos); + mQSB.getLocationOnScreen(pos); final Rect rect = new Rect(); rect.left = pos[0]; rect.top = pos[1]; - rect.right = pos[0] + mQSBSearchBar.getWidth(); - rect.bottom = pos[1] + mQSBSearchBar.getHeight(); + rect.right = pos[0] + mQSB.getWidth(); + rect.bottom = pos[1] + mQSB.getHeight(); return rect; } else { return null; @@ -230,8 +239,8 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D } public void enableAccessibleDrag(boolean enable) { - if (mQSBSearchBar != null) { - mQSBSearchBar.setVisibility(enable ? View.GONE : View.VISIBLE); + if (mQSB != null) { + mQSB.setVisibility(enable ? View.GONE : View.VISIBLE); } mInfoDropTarget.enableAccessibleDrag(enable); mDeleteDropTarget.enableAccessibleDrag(enable); diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 086934773..bbcabe1c2 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -178,7 +178,24 @@ public class Workspace extends PagedView // State variable that indicates whether the pages are small (ie when you're // in all apps or customize mode) - enum State { NORMAL, NORMAL_HIDDEN, SPRING_LOADED, OVERVIEW, OVERVIEW_HIDDEN}; + enum State { + NORMAL (SearchDropTargetBar.State.SEARCH_BAR), + NORMAL_HIDDEN (SearchDropTargetBar.State.INVISIBLE), + SPRING_LOADED (SearchDropTargetBar.State.DROP_TARGET), + OVERVIEW (SearchDropTargetBar.State.INVISIBLE), + OVERVIEW_HIDDEN (SearchDropTargetBar.State.INVISIBLE); + + private final SearchDropTargetBar.State mBarState; + + State(SearchDropTargetBar.State searchBarState) { + mBarState = searchBarState; + } + + public SearchDropTargetBar.State getSearchDropTargetBarState() { + return mBarState; + } + }; + private State mState = State.NORMAL; private boolean mIsSwitchingState = false; @@ -1567,7 +1584,7 @@ public class Workspace extends PagedView // Reset our click listener setOnClickListener(mLauncher); } - mLauncher.getSearchBar().enableAccessibleDrag(enable); + mLauncher.getSearchDropTargetBar().enableAccessibleDrag(enable); mLauncher.getHotseat().getLayout() .enableAccessibleDrag(enable, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG); } @@ -1971,10 +1988,10 @@ public class Workspace extends PagedView * to that new state. */ public Animator setStateWithAnimation(State toState, int toPage, boolean animated, - boolean hasOverlaySearchBar, HashMap layerViews) { + HashMap layerViews) { // Create the animation to the new state Animator workspaceAnim = mStateTransitionAnimation.getAnimationToState(mState, - toState, toPage, animated, hasOverlaySearchBar, layerViews); + toState, toPage, animated, layerViews); // Update the current state mState = toState; diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index e908ccd81..54f63bbd8 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -218,16 +218,13 @@ public class WorkspaceStateTransitionAnimation { } public AnimatorSet getAnimationToState(Workspace.State fromState, Workspace.State toState, - int toPage, boolean animated, boolean hasOverlaySearchBar, - HashMap layerViews) { + int toPage, boolean animated, HashMap layerViews) { AccessibilityManager am = (AccessibilityManager) mLauncher.getSystemService(Context.ACCESSIBILITY_SERVICE); final boolean accessibilityEnabled = am.isEnabled(); TransitionStates states = new TransitionStates(fromState, toState); - int duration = getAnimationDuration(states); - animateWorkspace(states, toPage, animated, duration, layerViews, - accessibilityEnabled); - animateSearchBar(states, animated, duration, hasOverlaySearchBar, layerViews, + int workspaceDuration = getAnimationDuration(states); + animateWorkspace(states, toPage, animated, workspaceDuration, layerViews, accessibilityEnabled); animateBackgroundGradient(states, animated, BACKGROUND_FADE_OUT_DURATION); return mStateAnimator; @@ -473,76 +470,10 @@ public class WorkspaceStateTransitionAnimation { } } - /** - * Coordinates with the workspace animation to animate the search bar. - * - * TODO: This should really be coordinated with the SearchDropTargetBar, otherwise the - * bar has no idea that it is hidden, and this has no idea what state the bar is - * actually in. - */ - private void animateSearchBar(TransitionStates states, boolean animated, int duration, - boolean hasOverlaySearchBar, final HashMap layerViews, - final boolean accessibilityEnabled) { - - // The search bar is only visible in the workspace - final View searchBar = mLauncher.getOrCreateQsbBar(); - if (searchBar != null) { - final boolean searchBarWillBeShown = states.stateIsNormal; - final float finalSearchBarAlpha = searchBarWillBeShown ? 1f : 0f; - if (animated) { - if (hasOverlaySearchBar) { - // If there is an overlay search bar, then we will coordinate with it. - mStateAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - // If we are transitioning to a visible search bar, show it immediately - // and let the overlay search bar has faded out - if (searchBarWillBeShown) { - searchBar.setAlpha(finalSearchBarAlpha); - AlphaUpdateListener.updateVisibility(searchBar, accessibilityEnabled); - } - } - - @Override - public void onAnimationEnd(Animator animation) { - // If we are transitioning to a hidden search bar, hide it only after - // the overlay search bar has faded in - if (!searchBarWillBeShown) { - searchBar.setAlpha(finalSearchBarAlpha); - AlphaUpdateListener.updateVisibility(searchBar, accessibilityEnabled); - } - } - }); - } else { - // Otherwise, we can just do the normal animation - LauncherViewPropertyAnimator searchBarAlpha = - new LauncherViewPropertyAnimator(searchBar).alpha(finalSearchBarAlpha); - searchBarAlpha.addListener(new AlphaUpdateListener(searchBar, - accessibilityEnabled)); - searchBar.setLayerType(View.LAYER_TYPE_HARDWARE, null); - if (layerViews != null) { - // If layerViews is not null, we add these views, and indicate that - // the caller can manage layer state. - layerViews.put(searchBar, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER); - } else { - // Otherwise let the animator handle layer management. - searchBarAlpha.withLayer(); - } - searchBarAlpha.setDuration(duration); - mStateAnimator.play(searchBarAlpha); - } - } else { - // Set the search bar state immediately - searchBar.setAlpha(finalSearchBarAlpha); - AlphaUpdateListener.updateVisibility(searchBar, accessibilityEnabled); - } - } - } - /** * Animates the background scrim. Add to the state animator to prevent jankiness. * - * @param finalAlpha the final alpha for the background scrim + * @param states the current and final workspace states * @param animated whether or not to set the background alpha immediately * @duration duration of the animation */ -- cgit v1.2.3 From d1ea63f24a751521e6c35cc06be0e548e0b04f23 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 5 Aug 2015 12:32:47 -0700 Subject: Removing some synthetic method creation Change-Id: Icb6b38f78aa56ad2c11e2ccc8005994ac4b86a91 --- src/com/android/launcher3/LauncherStateTransitionAnimation.java | 2 +- src/com/android/launcher3/SearchDropTargetBar.java | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java index acace8299..5a3f3dc7a 100644 --- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java +++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java @@ -792,7 +792,7 @@ public class LauncherStateTransitionAnimation { } } - private void cleanupAnimation() { + @Thunk void cleanupAnimation() { mCurrentAnimation = null; } } diff --git a/src/com/android/launcher3/SearchDropTargetBar.java b/src/com/android/launcher3/SearchDropTargetBar.java index fe89c15a7..1efdfb62d 100644 --- a/src/com/android/launcher3/SearchDropTargetBar.java +++ b/src/com/android/launcher3/SearchDropTargetBar.java @@ -26,6 +26,8 @@ import android.view.accessibility.AccessibilityManager; import android.view.animation.AccelerateInterpolator; import android.widget.FrameLayout; +import com.android.launcher3.util.Thunk; + /* * Ths bar will manage the transition between the QSB search bar and the delete drop * targets so that each of the individual IconDropTargets don't have to. @@ -63,10 +65,10 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D new AccelerateInterpolator(); private State mState = State.SEARCH_BAR; - private View mQSB; - private View mDropTargetBar; + @Thunk View mQSB; + @Thunk View mDropTargetBar; private boolean mDeferOnDragEnd = false; - private boolean mAccessibilityEnabled = false; + @Thunk boolean mAccessibilityEnabled = false; // Drop targets private ButtonDropTarget mInfoDropTarget; -- cgit v1.2.3 From a2a039b66f05a1164f954387b1c12a8fb4063e92 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 5 Aug 2015 13:22:21 -0700 Subject: Using a reverse hashmap instead of indexOfValue in userManager Bug: 22980139 Change-Id: I87b633d194ff4e1529dd679dc02da573ed374207 --- src/com/android/launcher3/WidgetPreviewLoader.java | 11 +---------- .../launcher3/compat/UserManagerCompatV17.java | 19 ++++++++++++++----- .../android/launcher3/compat/UserManagerCompatVL.java | 14 ++++++++------ 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java index 1fb795add..3d5058769 100644 --- a/src/com/android/launcher3/WidgetPreviewLoader.java +++ b/src/com/android/launcher3/WidgetPreviewLoader.java @@ -212,7 +212,6 @@ public class WidgetPreviewLoader { public void removeObsoletePreviews(ArrayList list) { Utilities.assertWorkerThread(); - LongSparseArray userIdCache = new LongSparseArray<>(); LongSparseArray> validPackages = new LongSparseArray<>(); for (Object obj : list) { @@ -227,15 +226,7 @@ public class WidgetPreviewLoader { pkg = info.provider.getPackageName(); } - int userIdIndex = userIdCache.indexOfValue(user); - final long userId; - if (userIdIndex < 0) { - userId = mUserManager.getSerialNumberForUser(user); - userIdCache.put(userId, user); - } else { - userId = userIdCache.keyAt(userIdIndex); - } - + final long userId = mUserManager.getSerialNumberForUser(user); HashSet packages = validPackages.get(userId); if (packages == null) { packages = new HashSet<>(); diff --git a/src/com/android/launcher3/compat/UserManagerCompatV17.java b/src/com/android/launcher3/compat/UserManagerCompatV17.java index 1687569f3..75203b7f3 100644 --- a/src/com/android/launcher3/compat/UserManagerCompatV17.java +++ b/src/com/android/launcher3/compat/UserManagerCompatV17.java @@ -23,10 +23,16 @@ import android.os.UserManager; import com.android.launcher3.util.LongArrayMap; +import java.util.HashMap; + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public class UserManagerCompatV17 extends UserManagerCompatV16 { protected LongArrayMap mUsers; + // Create a separate reverse map as LongArrayMap.indexOfValue checks if objects are same + // and not {@link Object#equals} + protected HashMap mUserToSerialMap; + protected UserManager mUserManager; UserManagerCompatV17(Context context) { @@ -35,9 +41,9 @@ public class UserManagerCompatV17 extends UserManagerCompatV16 { public long getSerialNumberForUser(UserHandleCompat user) { synchronized (this) { - if (mUsers != null) { - int index = mUsers.indexOfValue(user); - return (index >= 0) ? mUsers.keyAt(index) : 0; + if (mUserToSerialMap != null) { + Long serial = mUserToSerialMap.get(user); + return serial == null ? 0 : serial; } } return mUserManager.getSerialNumberForUser(user.getUser()); @@ -55,9 +61,12 @@ public class UserManagerCompatV17 extends UserManagerCompatV16 { @Override public void enableAndResetCache() { synchronized (this) { - mUsers = new LongArrayMap(); + mUsers = new LongArrayMap<>(); + mUserToSerialMap = new HashMap<>(); UserHandleCompat myUser = UserHandleCompat.myUserHandle(); - mUsers.put(mUserManager.getSerialNumberForUser(myUser.getUser()), myUser); + long serial = mUserManager.getSerialNumberForUser(myUser.getUser()); + mUsers.put(serial, myUser); + mUserToSerialMap.put(myUser, serial); } } } diff --git a/src/com/android/launcher3/compat/UserManagerCompatVL.java b/src/com/android/launcher3/compat/UserManagerCompatVL.java index 04cd0fdb4..4d404db2b 100644 --- a/src/com/android/launcher3/compat/UserManagerCompatVL.java +++ b/src/com/android/launcher3/compat/UserManagerCompatVL.java @@ -30,6 +30,7 @@ import com.android.launcher3.util.LongArrayMap; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; @TargetApi(Build.VERSION_CODES.LOLLIPOP) @@ -48,12 +49,15 @@ public class UserManagerCompatVL extends UserManagerCompatV17 { @Override public void enableAndResetCache() { synchronized (this) { - mUsers = new LongArrayMap(); + mUsers = new LongArrayMap<>(); + mUserToSerialMap = new HashMap<>(); List users = mUserManager.getUserProfiles(); if (users != null) { for (UserHandle user : users) { - mUsers.put(mUserManager.getSerialNumberForUser(user), - UserHandleCompat.fromUser(user)); + long serial = mUserManager.getSerialNumberForUser(user); + UserHandleCompat userCompat = UserHandleCompat.fromUser(user); + mUsers.put(serial, userCompat); + mUserToSerialMap.put(userCompat, serial); } } } @@ -64,9 +68,7 @@ public class UserManagerCompatVL extends UserManagerCompatV17 { synchronized (this) { if (mUsers != null) { List users = new ArrayList<>(); - for (UserHandleCompat user : mUsers) { - users.add(user); - } + users.addAll(mUserToSerialMap.keySet()); return users; } } -- cgit v1.2.3 From a1f79d3e16362d16c06b18fd5a06d93be9bbf1fd Mon Sep 17 00:00:00 2001 From: Winson Date: Wed, 5 Aug 2015 14:00:45 -0700 Subject: Fixing invisible search bar - We used to rely on the state transition to inflate the search widget after the permission to bind widgets was granted, which is fragile. Now we try and inflate the search widget after user grants the permission if necessary. Bug: 22515084 Bug: 22980143 Change-Id: Id111d263bc8a864e0fa652cfd0e07e66ec690fe7 --- src/com/android/launcher3/Launcher.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 9d04770af..32e7ee681 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -742,6 +742,7 @@ public class Launcher extends Activity }; if (requestCode == REQUEST_BIND_APPWIDGET) { + // This is called only if the user did not previously have permissions to bind widgets final int appWidgetId = data != null ? data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1) : -1; if (resultCode == RESULT_CANCELED) { @@ -751,6 +752,10 @@ public class Launcher extends Activity } else if (resultCode == RESULT_OK) { addAppWidgetImpl(appWidgetId, mPendingAddInfo, null, mPendingAddWidgetInfo, ON_ACTIVITY_RESULT_ANIMATION_DELAY); + + // When the user has granted permission to bind widgets, we should check to see if + // we can inflate the default search bar widget. + getOrCreateQsbBar(); } return; } else if (requestCode == REQUEST_PICK_WALLPAPER) { -- cgit v1.2.3 From bedf9232eb67a420f0372d3ca135ca13194e603b Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 10 Jul 2015 12:38:30 -0700 Subject: Adding market search. Change-Id: Id41615653cd4fa76213add4595418ad0cc6e7852 --- res/drawable-hdpi/ic_arrow_back_grey.png | Bin 190 -> 152 bytes res/drawable-hdpi/ic_search_grey.png | Bin 743 -> 419 bytes res/drawable-mdpi/ic_arrow_back_grey.png | Bin 151 -> 117 bytes res/drawable-mdpi/ic_search_grey.png | Bin 497 -> 263 bytes res/drawable-v21/all_apps_search_market_bg.xml | 19 +++ res/drawable-xhdpi/ic_arrow_back_grey.png | Bin 234 -> 151 bytes res/drawable-xhdpi/ic_search_grey.png | Bin 972 -> 497 bytes res/drawable-xxhdpi/ic_arrow_back_grey.png | Bin 308 -> 190 bytes res/drawable-xxhdpi/ic_search_grey.png | Bin 1473 -> 743 bytes res/drawable-xxxhdpi/ic_arrow_back_grey.png | Bin 359 -> 234 bytes res/drawable-xxxhdpi/ic_search_grey.png | Bin 1996 -> 972 bytes res/drawable/all_apps_search_market_bg.xml | 20 ++++ res/drawable/horizontal_line.xml | 21 ++++ res/layout/all_apps_empty_search.xml | 15 ++- res/layout/all_apps_search_bar.xml | 13 +-- res/layout/all_apps_search_market.xml | 29 +++++ res/layout/all_apps_search_market_divider.xml | 27 +++++ res/values/colors.xml | 1 + res/values/strings.xml | 7 +- src/com/android/launcher3/Launcher.java | 15 ++- src/com/android/launcher3/LauncherCallbacks.java | 1 + .../launcher3/allapps/AllAppsContainerView.java | 31 ++--- .../launcher3/allapps/AllAppsGridAdapter.java | 130 +++++++++++++++------ .../launcher3/allapps/AllAppsRecyclerView.java | 2 + .../launcher3/allapps/AlphabeticalAppsList.java | 59 ++++++++-- .../allapps/DefaultAppSearchController.java | 18 +-- .../launcher3/testing/LauncherExtension.java | 5 + 27 files changed, 326 insertions(+), 87 deletions(-) create mode 100644 res/drawable-v21/all_apps_search_market_bg.xml create mode 100644 res/drawable/all_apps_search_market_bg.xml create mode 100644 res/drawable/horizontal_line.xml create mode 100644 res/layout/all_apps_search_market.xml create mode 100644 res/layout/all_apps_search_market_divider.xml diff --git a/res/drawable-hdpi/ic_arrow_back_grey.png b/res/drawable-hdpi/ic_arrow_back_grey.png index ccd3900dd..c7c00886f 100755 Binary files a/res/drawable-hdpi/ic_arrow_back_grey.png and b/res/drawable-hdpi/ic_arrow_back_grey.png differ diff --git a/res/drawable-hdpi/ic_search_grey.png b/res/drawable-hdpi/ic_search_grey.png index f4c5e27d2..bd20ba062 100755 Binary files a/res/drawable-hdpi/ic_search_grey.png and b/res/drawable-hdpi/ic_search_grey.png differ diff --git a/res/drawable-mdpi/ic_arrow_back_grey.png b/res/drawable-mdpi/ic_arrow_back_grey.png index 11996efe3..5892c77d5 100755 Binary files a/res/drawable-mdpi/ic_arrow_back_grey.png and b/res/drawable-mdpi/ic_arrow_back_grey.png differ diff --git a/res/drawable-mdpi/ic_search_grey.png b/res/drawable-mdpi/ic_search_grey.png index e83891c11..c386dbb38 100755 Binary files a/res/drawable-mdpi/ic_search_grey.png and b/res/drawable-mdpi/ic_search_grey.png differ diff --git a/res/drawable-v21/all_apps_search_market_bg.xml b/res/drawable-v21/all_apps_search_market_bg.xml new file mode 100644 index 000000000..7bd2f8816 --- /dev/null +++ b/res/drawable-v21/all_apps_search_market_bg.xml @@ -0,0 +1,19 @@ + + + + + diff --git a/res/drawable-xhdpi/ic_arrow_back_grey.png b/res/drawable-xhdpi/ic_arrow_back_grey.png index 79b9b486c..11996efe3 100755 Binary files a/res/drawable-xhdpi/ic_arrow_back_grey.png and b/res/drawable-xhdpi/ic_arrow_back_grey.png differ diff --git a/res/drawable-xhdpi/ic_search_grey.png b/res/drawable-xhdpi/ic_search_grey.png index bd5fdf444..e83891c11 100755 Binary files a/res/drawable-xhdpi/ic_search_grey.png and b/res/drawable-xhdpi/ic_search_grey.png differ diff --git a/res/drawable-xxhdpi/ic_arrow_back_grey.png b/res/drawable-xxhdpi/ic_arrow_back_grey.png index 8e42e091d..ccd3900dd 100755 Binary files a/res/drawable-xxhdpi/ic_arrow_back_grey.png and b/res/drawable-xxhdpi/ic_arrow_back_grey.png differ diff --git a/res/drawable-xxhdpi/ic_search_grey.png b/res/drawable-xxhdpi/ic_search_grey.png index 1d5c91361..f4c5e27d2 100755 Binary files a/res/drawable-xxhdpi/ic_search_grey.png and b/res/drawable-xxhdpi/ic_search_grey.png differ diff --git a/res/drawable-xxxhdpi/ic_arrow_back_grey.png b/res/drawable-xxxhdpi/ic_arrow_back_grey.png index 854a9bd1a..79b9b486c 100755 Binary files a/res/drawable-xxxhdpi/ic_arrow_back_grey.png and b/res/drawable-xxxhdpi/ic_arrow_back_grey.png differ diff --git a/res/drawable-xxxhdpi/ic_search_grey.png b/res/drawable-xxxhdpi/ic_search_grey.png index 28519fda6..bd5fdf444 100755 Binary files a/res/drawable-xxxhdpi/ic_search_grey.png and b/res/drawable-xxxhdpi/ic_search_grey.png differ diff --git a/res/drawable/all_apps_search_market_bg.xml b/res/drawable/all_apps_search_market_bg.xml new file mode 100644 index 000000000..5278e00a6 --- /dev/null +++ b/res/drawable/all_apps_search_market_bg.xml @@ -0,0 +1,20 @@ + + + + + + + diff --git a/res/drawable/horizontal_line.xml b/res/drawable/horizontal_line.xml new file mode 100644 index 000000000..3f3f17e35 --- /dev/null +++ b/res/drawable/horizontal_line.xml @@ -0,0 +1,21 @@ + + + + + + diff --git a/res/layout/all_apps_empty_search.xml b/res/layout/all_apps_empty_search.xml index f60c4a09a..b9b493eab 100644 --- a/res/layout/all_apps_empty_search.xml +++ b/res/layout/all_apps_empty_search.xml @@ -18,11 +18,14 @@ android:id="@+id/empty_text" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:gravity="center" - android:paddingTop="24dp" - android:paddingBottom="24dp" - android:paddingRight="@dimen/all_apps_grid_view_start_margin" - android:textSize="16sp" - android:textColor="#4c4c4c" + android:gravity="start" + android:paddingTop="20dp" + android:paddingBottom="8dp" + android:paddingLeft="16dp" + android:paddingRight="16dp" + android:fontFamily="sans-serif-medium" + android:textSize="14sp" + android:textColor="#212121" + android:alpha="0.56" android:focusable="false" /> diff --git a/res/layout/all_apps_search_bar.xml b/res/layout/all_apps_search_bar.xml index cf30eac36..4947203df 100644 --- a/res/layout/all_apps_search_bar.xml +++ b/res/layout/all_apps_search_bar.xml @@ -32,11 +32,10 @@ android:id="@+id/dismiss_search_button" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="4dp" - android:layout_marginStart="4dp" + android:layout_gravity="center_vertical" + android:layout_marginLeft="16dp" + android:layout_marginStart="16dp" android:contentDescription="@string/all_apps_button_label" - android:paddingBottom="13dp" - android:paddingTop="13dp" android:src="@drawable/ic_arrow_back_grey" /> \ No newline at end of file diff --git a/res/layout/all_apps_search_market.xml b/res/layout/all_apps_search_market.xml new file mode 100644 index 000000000..1282069c8 --- /dev/null +++ b/res/layout/all_apps_search_market.xml @@ -0,0 +1,29 @@ + + + diff --git a/res/layout/all_apps_search_market_divider.xml b/res/layout/all_apps_search_market_divider.xml new file mode 100644 index 000000000..39097818f --- /dev/null +++ b/res/layout/all_apps_search_market_divider.xml @@ -0,0 +1,27 @@ + + + \ No newline at end of file diff --git a/res/values/colors.xml b/res/values/colors.xml index 51e4d40a5..0add48cd8 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -44,6 +44,7 @@ #009688 + #DDDDDD #42FFFFFF diff --git a/res/values/strings.xml b/res/values/strings.xml index 88f149bd0..fefadef28 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -24,10 +24,10 @@ content://com.android.launcher2.settings/favorites?notify=true - + com.android.launcher3.permission.RECEIVE_LAUNCH_BROADCASTS - + com.android.launcher3.permission.RECEIVE_FIRST_LOAD_BROADCAST @@ -61,6 +61,9 @@ Loading Apps… No Apps found matching \"%1$s\" + + Go to %1$s diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 9d04770af..2d338e3d4 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -2132,6 +2132,15 @@ public class Launcher extends Activity } } + public void startSearchFromAllApps(View v, Intent searchIntent, String searchQuery) { + if (mLauncherCallbacks != null && mLauncherCallbacks.startSearchFromAllApps(searchQuery)) { + return; + } + + // If not handled, then just start the provided search intent + startActivitySafely(v, searchIntent, null); + } + public boolean isOnCustomContent() { return mWorkspace.isOnOrMovingToCustomContent(); } @@ -2533,6 +2542,10 @@ public class Launcher extends Activity if (!isAppsViewVisible()) { showAppsView(true /* animated */, false /* resetListToTop */, true /* updatePredictedApps */, false /* focusSearchBar */); + + if (mLauncherCallbacks != null) { + mLauncherCallbacks.onClickAllAppsButton(v); + } } } @@ -2924,7 +2937,7 @@ public class Launcher extends Activity return false; } - @Thunk boolean startActivitySafely(View v, Intent intent, Object tag) { + public boolean startActivitySafely(View v, Intent intent, Object tag) { boolean success = false; if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) { Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show(); diff --git a/src/com/android/launcher3/LauncherCallbacks.java b/src/com/android/launcher3/LauncherCallbacks.java index 6618cca78..e34bd57fd 100644 --- a/src/com/android/launcher3/LauncherCallbacks.java +++ b/src/com/android/launcher3/LauncherCallbacks.java @@ -77,6 +77,7 @@ public interface LauncherCallbacks { public boolean providesSearch(); public boolean startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData, Rect sourceBounds); + public boolean startSearchFromAllApps(String query); @Deprecated public void startVoice(); public boolean hasCustomContentToLeft(); diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 010b2cb48..e129dc6d3 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -16,34 +16,26 @@ package com.android.launcher3.allapps; import android.annotation.SuppressLint; -import android.annotation.TargetApi; import android.content.Context; +import android.content.Intent; import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.InsetDrawable; -import android.os.Build; -import android.os.Bundle; import android.support.v7.widget.RecyclerView; import android.text.Selection; import android.text.SpannableStringBuilder; import android.text.method.TextKeyListener; import android.util.AttributeSet; import android.view.KeyEvent; -import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import android.widget.FrameLayout; import android.widget.LinearLayout; - import com.android.launcher3.AppInfo; import com.android.launcher3.BaseContainerView; -import com.android.launcher3.BubbleTextView; import com.android.launcher3.CellLayout; -import com.android.launcher3.CheckLongPressHelper; import com.android.launcher3.DeleteDropTarget; import com.android.launcher3.DeviceProfile; import com.android.launcher3.DragSource; @@ -53,7 +45,6 @@ import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherTransitionable; import com.android.launcher3.R; -import com.android.launcher3.Stats; import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; import com.android.launcher3.util.ComponentKey; @@ -155,6 +146,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc @Thunk AllAppsSearchBarController mSearchBarController; private ViewGroup mSearchBarContainerView; private View mSearchBarView; + private SpannableStringBuilder mSearchQueryBuilder = null; private int mSectionNamesMargin; private int mNumAppsPerRow; @@ -165,7 +157,13 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc // This coordinate is relative to its parent private final Point mIconLastTouchPos = new Point(); - private SpannableStringBuilder mSearchQueryBuilder = null; + private View.OnClickListener mSearchClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent searchIntent = (Intent) v.getTag(); + mLauncher.startActivitySafely(v, searchIntent, null); + } + }; public AllAppsContainerView(Context context) { this(context, null); @@ -182,8 +180,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc mLauncher = (Launcher) context; mSectionNamesMargin = res.getDimensionPixelSize(R.dimen.all_apps_grid_view_start_margin); mApps = new AlphabeticalAppsList(context); - mAdapter = new AllAppsGridAdapter(context, mApps, this, mLauncher, this); - mAdapter.setEmptySearchText(res.getString(R.string.all_apps_loading_message)); + mAdapter = new AllAppsGridAdapter(mLauncher, mApps, this, mLauncher, this); mApps.setAdapter(mAdapter); mLayoutManager = mAdapter.getLayoutManager(); mItemDecoration = mAdapter.getItemDecoration(); @@ -615,13 +612,9 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc @Override public void onSearchResult(String query, ArrayList apps) { if (apps != null) { - if (apps.isEmpty()) { - String formatStr = getResources().getString(R.string.all_apps_no_search_results); - mAdapter.setEmptySearchText(String.format(formatStr, query)); - } else { - mAppsRecyclerView.scrollToTop(); - } mApps.setOrderedFilter(apps); + mAdapter.setLastSearchQuery(query); + mAppsRecyclerView.scrollToTop(); } } diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java index e96567c41..4acfc5ca6 100644 --- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java +++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java @@ -16,14 +16,17 @@ package com.android.launcher3.allapps; import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PointF; import android.graphics.Rect; -import android.os.Handler; import android.support.v4.view.accessibility.AccessibilityRecordCompat; import android.support.v4.view.accessibility.AccessibilityEventCompat; +import android.net.Uri; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; @@ -34,6 +37,7 @@ import android.view.accessibility.AccessibilityEvent; import android.widget.TextView; import com.android.launcher3.AppInfo; import com.android.launcher3.BubbleTextView; +import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.util.Thunk; @@ -58,6 +62,10 @@ class AllAppsGridAdapter extends RecyclerView.Adapter 1) { return false; } - // If there is exactly one icon, then quick-launch it + // Otherwise, find the first icon, or fallback to the search-market-view and launch it List items = mApps.getAdapterItems(); for (int i = 0; i < items.size(); i++) { AlphabeticalAppsList.AdapterItem item = items.get(i); - if (item.viewType == AllAppsGridAdapter.ICON_VIEW_TYPE) { - mAppsRecyclerView.getChildAt(i).performClick(); - mInputMethodManager.hideSoftInputFromWindow( - mContainerView.getWindowToken(), 0); - return true; + switch (item.viewType) { + case AllAppsGridAdapter.ICON_VIEW_TYPE: + case AllAppsGridAdapter.SEARCH_MARKET_VIEW_TYPE: + mAppsRecyclerView.getChildAt(i).performClick(); + mInputMethodManager.hideSoftInputFromWindow( + mContainerView.getWindowToken(), 0); + return true; } } return false; diff --git a/src/com/android/launcher3/testing/LauncherExtension.java b/src/com/android/launcher3/testing/LauncherExtension.java index 34492e4ca..8702877bf 100644 --- a/src/com/android/launcher3/testing/LauncherExtension.java +++ b/src/com/android/launcher3/testing/LauncherExtension.java @@ -201,6 +201,11 @@ public class LauncherExtension extends Launcher { return false; } + @Override + public boolean startSearchFromAllApps(String query) { + return false; + } + @Override public void startVoice() { } -- cgit v1.2.3 From cf0c746ec080ee528d4994c382562fda1e647752 Mon Sep 17 00:00:00 2001 From: Adam Cohen Date: Thu, 6 Aug 2015 14:02:23 -0700 Subject: Always log if Package is missing while loading default workspace Change-Id: I7f2e5a9aabdf1fc192ad7912aaefa3f41c059ff1 --- src/com/android/launcher3/AutoInstallsLayout.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/AutoInstallsLayout.java b/src/com/android/launcher3/AutoInstallsLayout.java index 99a98ddac..440e4e7b9 100644 --- a/src/com/android/launcher3/AutoInstallsLayout.java +++ b/src/com/android/launcher3/AutoInstallsLayout.java @@ -355,7 +355,7 @@ public class AutoInstallsLayout { return addShortcut(info.loadLabel(mPackageManager).toString(), intent, Favorites.ITEM_TYPE_APPLICATION); } catch (PackageManager.NameNotFoundException e) { - if (LOGD) Log.w(TAG, "Unable to add favorite: " + packageName + "/" + className, e); + Log.e(TAG, "Unable to add favorite: " + packageName + "/" + className, e); } return -1; } else { @@ -367,7 +367,7 @@ public class AutoInstallsLayout { * Helper method to allow extending the parser capabilities */ protected long invalidPackageOrClass(XmlResourceParser parser) { - if (LOGD) Log.d(TAG, "Skipping invalid with no component"); + Log.w(TAG, "Skipping invalid with no component"); return -1; } } -- cgit v1.2.3 From b0ca1a225f99a0a9b70419ed11e313b78ea1425c Mon Sep 17 00:00:00 2001 From: Winson Date: Thu, 6 Aug 2015 14:42:50 -0700 Subject: Fixing issue with miscalculation in updating container bounds. - There was an issue with the previous logic where the test of whether the search bounds changed would always be false if valid search bounds were given. This in conjunction with the fact that the padding was changed to only take the bounds left/right into account, meant that the container bounds would not be updated if the search bar bounds shifted via the insets. Bug: 22918919 Change-Id: Ia810ddc7a56eae4afc0c7cd558fa6dc9e8e7a95b --- src/com/android/launcher3/BaseContainerView.java | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/com/android/launcher3/BaseContainerView.java b/src/com/android/launcher3/BaseContainerView.java index c8de9df10..c11824054 100644 --- a/src/com/android/launcher3/BaseContainerView.java +++ b/src/com/android/launcher3/BaseContainerView.java @@ -34,10 +34,12 @@ public abstract class BaseContainerView extends LinearLayout implements Insettab // The bounds of the search bar. Only the left, top, right are used to inset the // search bar and the height is determined by the measurement of the layout private Rect mFixedSearchBarBounds = new Rect(); - // The bounds of the container + // The computed bounds of the search bar + private Rect mSearchBarBounds = new Rect(); + // The computed bounds of the container protected Rect mContentBounds = new Rect(); - // The padding to apply to the container to achieve the bounds - protected Rect mContentPadding = new Rect(); + // The computed padding to apply to the container to achieve the container bounds + private Rect mContentPadding = new Rect(); // The inset to apply to the edges and between the search bar and the container private int mContainerBoundsInset; private boolean mHasSearchBar; @@ -90,7 +92,7 @@ public abstract class BaseContainerView extends LinearLayout implements Insettab */ protected void updateBackgroundAndPaddings() { Rect padding; - Rect searchBarBounds = new Rect(mFixedSearchBarBounds); + Rect searchBarBounds = new Rect(); if (!isValidSearchBarBounds(mFixedSearchBarBounds)) { // Use the default bounds padding = new Rect(mInsets.left + mContainerBoundsInset, @@ -110,14 +112,20 @@ public abstract class BaseContainerView extends LinearLayout implements Insettab (mHasSearchBar ? 0 : (mInsets.top + mContainerBoundsInset)), getMeasuredWidth() - mFixedSearchBarBounds.right, mInsets.bottom + mContainerBoundsInset); + + // Use the search bounds + searchBarBounds.set(mFixedSearchBarBounds); } - if (!padding.equals(mContentPadding) || !searchBarBounds.equals(mFixedSearchBarBounds)) { + + // If either the computed container padding has changed, or the computed search bar bounds + // has changed, then notify the container + if (!padding.equals(mContentPadding) || !searchBarBounds.equals(mSearchBarBounds)) { mContentPadding.set(padding); mContentBounds.set(padding.left, padding.top, getMeasuredWidth() - padding.right, getMeasuredHeight() - padding.bottom); - mFixedSearchBarBounds.set(searchBarBounds); - onUpdateBackgroundAndPaddings(mFixedSearchBarBounds, padding); + mSearchBarBounds.set(searchBarBounds); + onUpdateBackgroundAndPaddings(mSearchBarBounds, padding); } } -- cgit v1.2.3 From b33e09a93cda9793b84ec70e1d85c9038f5d3ee6 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 10 Aug 2015 11:53:23 -0700 Subject: Preventing user from selecting any new time, when a tile is already being applied Bug: 22293299 Change-Id: I6b9bf2b777d33ca23f291c7872ce1f338d41e516 --- .../src/com/android/launcher3/WallpaperPickerActivity.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java index c723b39be..069638f8c 100644 --- a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java +++ b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java @@ -551,6 +551,10 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { @Override public void onClick(View v) { if (mSelectedTile != null) { + // Prevent user from selecting any new tile. + mWallpaperStrip.setVisibility(View.GONE); + actionBar.hide(); + WallpaperTileInfo info = (WallpaperTileInfo) mSelectedTile.getTag(); info.onSave(WallpaperPickerActivity.this); } else { -- cgit v1.2.3 From 6579e1eee8a6fce44f020d40c3bbdbf245d6c12c Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 11 Aug 2015 12:10:34 -0700 Subject: Disabling home screen migration logic Change-Id: I506948852945bfb8ebd7a95fc951880ffe9a3e17 --- src/com/android/launcher3/LauncherBackupAgentHelper.java | 2 +- src/com/android/launcher3/LauncherBackupHelper.java | 4 +++- src/com/android/launcher3/LauncherModel.java | 3 +-- src/com/android/launcher3/model/MigrateFromRestoreTask.java | 2 ++ 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/com/android/launcher3/LauncherBackupAgentHelper.java b/src/com/android/launcher3/LauncherBackupAgentHelper.java index 611ab2e92..3debef60e 100644 --- a/src/com/android/launcher3/LauncherBackupAgentHelper.java +++ b/src/com/android/launcher3/LauncherBackupAgentHelper.java @@ -98,7 +98,7 @@ public class LauncherBackupAgentHelper extends BackupAgentHelper { LauncherAppState.getLauncherProvider().updateFolderItemsRank(); } - if (mHelper.shouldAttemptWorkspaceMigration()) { + if (MigrateFromRestoreTask.ENABLED && mHelper.shouldAttemptWorkspaceMigration()) { MigrateFromRestoreTask.markForMigration(getApplicationContext(), (int) mHelper.migrationCompatibleProfileData.desktopCols, (int) mHelper.migrationCompatibleProfileData.desktopRows, diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java index 136556b92..2d11d3af1 100644 --- a/src/com/android/launcher3/LauncherBackupHelper.java +++ b/src/com/android/launcher3/LauncherBackupHelper.java @@ -52,6 +52,7 @@ import com.android.launcher3.backup.BackupProtos.Screen; import com.android.launcher3.backup.BackupProtos.Widget; import com.android.launcher3.compat.UserHandleCompat; import com.android.launcher3.compat.UserManagerCompat; +import com.android.launcher3.model.MigrateFromRestoreTask; import com.android.launcher3.util.Thunk; import com.google.protobuf.nano.InvalidProtocolBufferNanoException; import com.google.protobuf.nano.MessageNano; @@ -314,7 +315,8 @@ public class LauncherBackupHelper implements BackupHelper { return true; } - if ((oldProfile.desktopCols - currentProfile.desktopCols <= 1) && + if (MigrateFromRestoreTask.ENABLED && + (oldProfile.desktopCols - currentProfile.desktopCols <= 1) && (oldProfile.desktopRows - currentProfile.desktopRows <= 1)) { // Allow desktop migration when row and/or column count contracts by 1. diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index f029561a3..d9b0cd490 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -1758,8 +1758,7 @@ public class LauncherModel extends BroadcastReceiver int countX = (int) profile.numColumns; int countY = (int) profile.numRows; - - if (MigrateFromRestoreTask.shouldRunTask(mContext)) { + if (MigrateFromRestoreTask.ENABLED && MigrateFromRestoreTask.shouldRunTask(mContext)) { long migrationStartTime = System.currentTimeMillis(); Log.v(TAG, "Starting workspace migration after restore"); try { diff --git a/src/com/android/launcher3/model/MigrateFromRestoreTask.java b/src/com/android/launcher3/model/MigrateFromRestoreTask.java index 8d4472fd1..6a529f61f 100644 --- a/src/com/android/launcher3/model/MigrateFromRestoreTask.java +++ b/src/com/android/launcher3/model/MigrateFromRestoreTask.java @@ -37,6 +37,8 @@ import java.util.HashSet; */ public class MigrateFromRestoreTask { + public static boolean ENABLED = false; + private static final String TAG = "MigrateFromRestoreTask"; private static final boolean DEBUG = true; -- cgit v1.2.3 From 3fcab663a141b31916152c8bc185b93b718d79df Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 11 Aug 2015 15:17:30 -0700 Subject: Preventing zoom-in animation from running everytime the app updates. Bug: 22557455 Change-Id: I3ac1212a2f319397cd18be8f4452047d974312b8 --- src/com/android/launcher3/PreloadIconDrawable.java | 4 ++++ src/com/android/launcher3/Workspace.java | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/PreloadIconDrawable.java b/src/com/android/launcher3/PreloadIconDrawable.java index bcb59c448..45e4b2c4a 100644 --- a/src/com/android/launcher3/PreloadIconDrawable.java +++ b/src/com/android/launcher3/PreloadIconDrawable.java @@ -213,6 +213,10 @@ class PreloadIconDrawable extends Drawable { return mAnimationProgress; } + public boolean hasNotCompleted() { + return mAnimationProgress < ANIMATION_PROGRESS_COMPLETED; + } + @Override public int getIntrinsicHeight() { return mIcon.getIntrinsicHeight(); diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 17e59a6d7..e83ef7c2b 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -4334,8 +4334,9 @@ public class Workspace extends PagedView updates.contains(info)) { ShortcutInfo si = (ShortcutInfo) info; BubbleTextView shortcut = (BubbleTextView) v; - boolean oldPromiseState = getTextViewIcon(shortcut) - instanceof PreloadIconDrawable; + Drawable oldIcon = getTextViewIcon(shortcut); + boolean oldPromiseState = (oldIcon instanceof PreloadIconDrawable) + && ((PreloadIconDrawable) oldIcon).hasNotCompleted(); shortcut.applyFromShortcutInfo(si, mIconCache, si.isPromise() != oldPromiseState); -- cgit v1.2.3 From eea9fa4022b9cdc5b2f65bbd9ed6b314c883248d Mon Sep 17 00:00:00 2001 From: Winson Date: Tue, 11 Aug 2015 16:20:47 -0700 Subject: Ensuring that AllAppsGridAdapter is public. - Also show the search action when searching all apps Change-Id: I3470b0da565e6d1bce637ce09384d966215a4ca7 --- res/layout/all_apps_search_bar.xml | 2 +- src/com/android/launcher3/allapps/AllAppsGridAdapter.java | 2 +- src/com/android/launcher3/allapps/DefaultAppSearchController.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/res/layout/all_apps_search_bar.xml b/res/layout/all_apps_search_bar.xml index cf30eac36..c1399715d 100644 --- a/res/layout/all_apps_search_bar.xml +++ b/res/layout/all_apps_search_bar.xml @@ -48,7 +48,7 @@ android:gravity="fill_horizontal|center_vertical" android:hint="@string/all_apps_search_bar_hint" android:inputType="text|textNoSuggestions|textCapWords" - android:imeOptions="actionDone|flagNoExtractUi" + android:imeOptions="actionSearch|flagNoExtractUi" android:maxLines="1" android:paddingLeft="8dp" android:scrollHorizontally="true" diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java index e96567c41..e613d50bc 100644 --- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java +++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java @@ -45,7 +45,7 @@ import java.util.List; /** * The grid view adapter of all the apps. */ -class AllAppsGridAdapter extends RecyclerView.Adapter { +public class AllAppsGridAdapter extends RecyclerView.Adapter { public static final String TAG = "AppsGridAdapter"; private static final boolean DEBUG = false; diff --git a/src/com/android/launcher3/allapps/DefaultAppSearchController.java b/src/com/android/launcher3/allapps/DefaultAppSearchController.java index 83b920589..39b48aada 100644 --- a/src/com/android/launcher3/allapps/DefaultAppSearchController.java +++ b/src/com/android/launcher3/allapps/DefaultAppSearchController.java @@ -166,7 +166,7 @@ final class DefaultAppSearchController extends AllAppsSearchBarController return false; } // Skip if it's not the right action - if (actionId != EditorInfo.IME_ACTION_DONE) { + if (actionId != EditorInfo.IME_ACTION_SEARCH) { return false; } // Skip if there isn't exactly one item -- cgit v1.2.3 From cc436d5d95af1aff9d486ce25f7965d159f871bb Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Tue, 11 Aug 2015 16:21:04 -0700 Subject: Fixing crash upon cancellation of an accessible drag. This fixes perhaps an old bug. If we started an accessible drag for an only item on a page, then uninstalled the app while dragging, the page was removed without unsetting its accessibility delegate. Later, the system asks the delegate to do something, but the drag is over, and some pointers are null, so everything crashes. Fixing this. Bug: 22028725 Change-Id: I85adcd42ae896603634994e20a7790792f7e84b1 (cherry picked from commit de1e67c38856ab1253426bfb4f892895eeb5f6d9) --- src/com/android/launcher3/Workspace.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index e83ef7c2b..08e642948 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -887,6 +887,9 @@ public class Workspace extends PagedView } } + LauncherAccessibilityDelegate delegate = + LauncherAppState.getInstance().getAccessibilityDelegate(); + // We enforce at least one page to add new items to. In the case that we remove the last // such screen, we convert the last screen to the empty screen int minScreens = 1 + numCustomPages(); @@ -901,6 +904,11 @@ public class Workspace extends PagedView if (indexOfChild(cl) < currentPage) { pageShift++; } + + if (delegate != null && delegate.isInAccessibleDrag()) { + cl.enableAccessibleDrag(false, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG); + } + removeView(cl); } else { // if this is the last non-custom content screen, convert it to the empty screen -- cgit v1.2.3 From 2d648b057fa2d6410b1472c1b9dd5b65cd9c9414 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 11 Aug 2015 13:56:28 -0700 Subject: Refreshing widget list when a package containing a widget changes Bug: 20698931 Change-Id: I50bafac1fc0a855edb1ace633a8a6f87a5c3040e --- .../android/launcher3/LauncherAppWidgetHost.java | 2 - src/com/android/launcher3/LauncherModel.java | 49 +++++++++++++++++----- src/com/android/launcher3/WidgetPreviewLoader.java | 2 +- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java index de7c61000..6c3a1e896 100644 --- a/src/com/android/launcher3/LauncherAppWidgetHost.java +++ b/src/com/android/launcher3/LauncherAppWidgetHost.java @@ -95,8 +95,6 @@ public class LauncherAppWidgetHost extends AppWidgetHost { } protected void onProvidersChanged() { - mLauncher.getModel().loadAndBindWidgetsAndShortcuts(mLauncher, mLauncher, - true /* refresh */); if (!mProviderChangeListeners.isEmpty()) { for (Runnable callback : new ArrayList<>(mProviderChangeListeners)) { callback.run(); diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index f029561a3..b854c1973 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -17,6 +17,7 @@ package com.android.launcher3; import android.app.SearchManager; +import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -2865,8 +2866,7 @@ public class LauncherModel extends BroadcastReceiver // Cleanup any data stored for a deleted user. ManagedProfileHeuristic.processAllUsers(profiles, mContext); - loadAndBindWidgetsAndShortcuts(mApp.getContext(), tryGetCallbacks(oldCallbacks), - true /* refresh */); + loadAndBindWidgetsAndShortcuts(tryGetCallbacks(oldCallbacks), true /* refresh */); if (DEBUG_LOADERS) { Log.d(TAG, "Icons processed in " + (SystemClock.uptimeMillis() - loadTime) + "ms"); @@ -2935,7 +2935,7 @@ public class LauncherModel extends BroadcastReceiver } // Reload widget list. No need to refresh, as we only want to update the icons and labels. - loadAndBindWidgetsAndShortcuts(mApp.getContext(), callbacks, false); + loadAndBindWidgetsAndShortcuts(callbacks, false); } void enqueuePackageUpdated(PackageUpdatedTask task) { @@ -3277,8 +3277,36 @@ public class LauncherModel extends BroadcastReceiver }); } - // onProvidersChanged method (API >= 17) already refreshed the widget list - loadAndBindWidgetsAndShortcuts(context, callbacks, Build.VERSION.SDK_INT < 17); + // Update widgets + if (mOp == OP_ADD || mOp == OP_REMOVE || mOp == OP_UPDATE) { + // Always refresh for a package event on secondary user + boolean needToRefresh = !mUser.equals(UserHandleCompat.myUserHandle()); + + // Refresh widget list, if the package already had a widget. + synchronized (sBgLock) { + if (sBgWidgetProviders != null) { + HashSet pkgSet = new HashSet<>(); + Collections.addAll(pkgSet, mPackages); + + for (ComponentKey key : sBgWidgetProviders.keySet()) { + needToRefresh |= key.user.equals(mUser) && + pkgSet.contains(key.componentName.getPackageName()); + } + } + } + + if (!needToRefresh && mOp != OP_REMOVE) { + // Refresh widget list, if there is any newly added widget + PackageManager pm = context.getPackageManager(); + for (String pkg : mPackages) { + needToRefresh |= !pm.queryBroadcastReceivers( + new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE) + .setPackage(pkg), 0).isEmpty(); + } + } + + loadAndBindWidgetsAndShortcuts(callbacks, needToRefresh); + } // Write all the logs to disk mHandler.post(new Runnable() { @@ -3352,13 +3380,12 @@ public class LauncherModel extends BroadcastReceiver } } - public void loadAndBindWidgetsAndShortcuts(final Context context, final Callbacks callbacks, - final boolean refresh) { + public void loadAndBindWidgetsAndShortcuts(final Callbacks callbacks, final boolean refresh) { runOnWorkerThread(new Runnable() { @Override public void run() { - updateWidgetsModel(context, refresh); + updateWidgetsModel(refresh); final WidgetsModel model = mBgWidgetsModel.clone(); mHandler.post(new Runnable() { @@ -3382,10 +3409,10 @@ public class LauncherModel extends BroadcastReceiver * * @see #loadAndBindWidgetsAndShortcuts */ - @Thunk void updateWidgetsModel(Context context, boolean refresh) { - PackageManager packageManager = context.getPackageManager(); + @Thunk void updateWidgetsModel(boolean refresh) { + PackageManager packageManager = mApp.getContext().getPackageManager(); final ArrayList widgetsAndShortcuts = new ArrayList(); - widgetsAndShortcuts.addAll(getWidgetProviders(context, refresh)); + widgetsAndShortcuts.addAll(getWidgetProviders(mApp.getContext(), refresh)); Intent shortcutsIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT); widgetsAndShortcuts.addAll(packageManager.queryIntentActivities(shortcutsIntent, 0)); mBgWidgetsModel.setWidgetsAndShortcuts(widgetsAndShortcuts); diff --git a/src/com/android/launcher3/WidgetPreviewLoader.java b/src/com/android/launcher3/WidgetPreviewLoader.java index 3d5058769..346055566 100644 --- a/src/com/android/launcher3/WidgetPreviewLoader.java +++ b/src/com/android/launcher3/WidgetPreviewLoader.java @@ -105,7 +105,7 @@ public class WidgetPreviewLoader { * sizes (landscape vs portrait). */ private static class CacheDb extends SQLiteOpenHelper { - private static final int DB_VERSION = 3; + private static final int DB_VERSION = 4; private static final String TABLE_NAME = "shortcut_and_widget_previews"; private static final String COLUMN_COMPONENT = "componentName"; -- cgit v1.2.3 From a09130b307796a7c2428cb3e2a250c0028ce51c8 Mon Sep 17 00:00:00 2001 From: Geoff Mendal Date: Wed, 12 Aug 2015 06:52:24 -0700 Subject: Import translations. DO NOT MERGE Change-Id: I6b0d7c6db67ef4de9a6ee0b7752cccf070223df4 Auto-generated-cl: translation import --- res/values-af/strings.xml | 1 + res/values-am/strings.xml | 1 + res/values-ar/strings.xml | 3 ++- res/values-az-rAZ/strings.xml | 1 + res/values-bg/strings.xml | 1 + res/values-bn-rBD/strings.xml | 1 + res/values-ca/strings.xml | 1 + res/values-cs/strings.xml | 1 + res/values-da/strings.xml | 1 + res/values-de/strings.xml | 1 + res/values-el/strings.xml | 1 + res/values-en-rAU/strings.xml | 1 + res/values-en-rGB/strings.xml | 1 + res/values-en-rIN/strings.xml | 1 + res/values-es-rUS/strings.xml | 1 + res/values-es/strings.xml | 1 + res/values-et-rEE/strings.xml | 1 + res/values-eu-rES/strings.xml | 1 + res/values-fa/strings.xml | 1 + res/values-fi/strings.xml | 1 + res/values-fr-rCA/strings.xml | 1 + res/values-fr/strings.xml | 1 + res/values-gl-rES/strings.xml | 1 + res/values-gu-rIN/strings.xml | 1 + res/values-hi/strings.xml | 1 + res/values-hr/strings.xml | 1 + res/values-hu/strings.xml | 1 + res/values-hy-rAM/strings.xml | 9 +++++---- res/values-in/strings.xml | 1 + res/values-is-rIS/strings.xml | 1 + res/values-it/strings.xml | 1 + res/values-iw/strings.xml | 1 + res/values-ja/strings.xml | 3 ++- res/values-ka-rGE/strings.xml | 2 ++ res/values-kk-rKZ/strings.xml | 1 + res/values-km-rKH/strings.xml | 1 + res/values-kn-rIN/strings.xml | 1 + res/values-ko/strings.xml | 1 + res/values-ky-rKG/strings.xml | 1 + res/values-lo-rLA/strings.xml | 1 + res/values-lt/strings.xml | 1 + res/values-lv/strings.xml | 1 + res/values-mk-rMK/strings.xml | 1 + res/values-ml-rIN/strings.xml | 1 + res/values-mn-rMN/strings.xml | 1 + res/values-mr-rIN/strings.xml | 1 + res/values-ms-rMY/strings.xml | 1 + res/values-my-rMM/strings.xml | 1 + res/values-nb/strings.xml | 1 + res/values-ne-rNP/strings.xml | 1 + res/values-nl/strings.xml | 1 + res/values-pa-rIN/strings.xml | 1 + res/values-pl/strings.xml | 1 + res/values-pt-rPT/strings.xml | 1 + res/values-pt/strings.xml | 1 + res/values-ro/strings.xml | 1 + res/values-ru/strings.xml | 1 + res/values-si-rLK/strings.xml | 1 + res/values-sk/strings.xml | 1 + res/values-sl/strings.xml | 1 + res/values-sq-rAL/strings.xml | 1 + res/values-sr/strings.xml | 1 + res/values-sv/strings.xml | 1 + res/values-sw/strings.xml | 1 + res/values-ta-rIN/strings.xml | 1 + res/values-te-rIN/strings.xml | 1 + res/values-th/strings.xml | 1 + res/values-tl/strings.xml | 1 + res/values-tr/strings.xml | 1 + res/values-uk/strings.xml | 1 + res/values-ur-rPK/strings.xml | 1 + res/values-uz-rUZ/strings.xml | 1 + res/values-vi/strings.xml | 1 + res/values-zh-rCN/strings.xml | 2 ++ res/values-zh-rHK/strings.xml | 1 + res/values-zh-rTW/strings.xml | 1 + res/values-zu/strings.xml | 1 + 77 files changed, 85 insertions(+), 6 deletions(-) diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml index 700452463..78be3f421 100644 --- a/res/values-af/strings.xml +++ b/res/values-af/strings.xml @@ -32,6 +32,7 @@ "Deursoek programme" "Laai tans programme …" "Geen programme gevind wat met \"%1$s\" ooreenstem nie" + "Gaan na %1$s" "Niks meer spasie op die tuisskerm nie." "Geen plek meer in die Gunstelinge-laai nie" "Programme" diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml index d7fed9de4..b5d982ee4 100644 --- a/res/values-am/strings.xml +++ b/res/values-am/strings.xml @@ -32,6 +32,7 @@ "መተግበሪያዎችን ይፈልጉ" "መተግበሪያዎችን በመጫን ላይ..." "ከ«%1$s» ጋር የሚዛመዱ ምንም መተግበሪያዎች አልተገኙም" + "ወደ %1$s ሂድ" "በዚህ መነሻ ማያ ገጽ ላይ ምንም ቦታ የለም።" "በተወዳጆች መሣቢያ ውስጥ ተጨማሪ ቦታ የለም" "መተግበሪያዎች" diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml index b7cd901de..619e11d67 100644 --- a/res/values-ar/strings.xml +++ b/res/values-ar/strings.xml @@ -32,12 +32,13 @@ "البحث في التطبيقات" "جارٍ تحميل التطبيقات…" "لم يتم العثور على أية تطبيقات تتطابق مع \"%1$s\"" + "الانتقال إلى %1$s" "ليس هناك مساحة أخرى في هذه الشاشة الرئيسية." "لا يوجد المزيد من الحقول في علبة المفضلة" "التطبيقات" "الرئيسية" "إزالة" - "إزالة" + "إلغاء التثبيت" "معلومات عن التطبيق" "تثبيت اختصارات" "للسماح لتطبيق ما بإضافة اختصارات بدون تدخل المستخدم." diff --git a/res/values-az-rAZ/strings.xml b/res/values-az-rAZ/strings.xml index 099a2208d..b9ea83f26 100644 --- a/res/values-az-rAZ/strings.xml +++ b/res/values-az-rAZ/strings.xml @@ -32,6 +32,7 @@ "Tətbiq Axtarın" "Tətbiqlər endirilir..." "\"%1$s\" sorğusuna uyğun Tətbiqlər tapılmadı" + "%1$s daxil olun" "Bu Əsas ekranda boş yer yoxdur." "Favoritlər-də yer yoxdur" "Tətbiqlər" diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml index eeaa1ede4..214c64b2d 100644 --- a/res/values-bg/strings.xml +++ b/res/values-bg/strings.xml @@ -32,6 +32,7 @@ "Търсене в приложенията" "Приложенията се зареждат…" "Няма намерени приложения, съответстващи на „%1$s“" + "Отваряне на %1$s" "На този начален екран няма повече място." "Няма повече място в областта с любимите" "Приложения" diff --git a/res/values-bn-rBD/strings.xml b/res/values-bn-rBD/strings.xml index 57f7b511d..129d2507a 100644 --- a/res/values-bn-rBD/strings.xml +++ b/res/values-bn-rBD/strings.xml @@ -32,6 +32,7 @@ "অ্যাপ্লিকেশানগুলি অনুসন্ধান করুন" "অ্যাপ্লিকেশানগুলি লোড হচ্ছে..." "\"%1$s\" এর সাথে মেলে এমন কোনো অ্যাপ্লিকেশান পাওয়া যায়নি" + "%1$s এ যান" "এই হোম স্ক্রীনে আর কোনো জায়গা নেই৷" "পছন্দসই ট্রে-তে আর কোনো জায়গা নেই" "অ্যাপ্লিকেশানগুলি" diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml index 83f284a9d..cf874a451 100644 --- a/res/values-ca/strings.xml +++ b/res/values-ca/strings.xml @@ -32,6 +32,7 @@ "Cerca a les aplicacions" "S\'estan carregant les aplicacions..." "No s\'ha trobat cap aplicació que coincideixi amb %1$s" + "Vés a %1$s" "Ja no queda espai en aquesta pantalla d\'inici." "No hi ha més espai a la safata Preferits." "Aplicacions" diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index c99a7ed84..c2f9f421b 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -32,6 +32,7 @@ "Hledat aplikace" "Načítání aplikací…" "Dotazu „%1$s“ neodpovídají žádné aplikace" + "Přejít na %1$s" "Na této ploše již není místo." "Na panelu Oblíbené položky již není místo." "Aplikace" diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml index eeab92e6e..a9487050e 100644 --- a/res/values-da/strings.xml +++ b/res/values-da/strings.xml @@ -32,6 +32,7 @@ "Søg i Apps" "Indlæser apps…" "Der blev ikke fundet nogen apps, som matcher \"%1$s\"" + "Gå til %1$s" "Der er ikke mere plads på denne startskærm." "Der er ikke mere plads i bakken Foretrukne" "Apps" diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index ac6f76b0c..96ae74b11 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -32,6 +32,7 @@ "In Apps suchen" "Apps werden geladen..." "Keine Apps für \"%1$s\" gefunden" + "Gehe zu %1$s" "Auf diesem Startbildschirm ist kein Platz mehr vorhanden." "Ablage \"Favoriten\" ist voll." "Apps" diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml index a60458a97..81b43e2e9 100644 --- a/res/values-el/strings.xml +++ b/res/values-el/strings.xml @@ -32,6 +32,7 @@ "Αναζήτηση εφαρμογών" "Φόρτωση εφαρμογών…" "Δεν βρέθηκαν εφαρμογές για το ερώτημα \"%1$s\"" + "Μετάβαση σε %1$s" "Δεν υπάρχει χώρος σε αυτήν την αρχική οθόνη." "Δεν υπάρχει επιπλέον χώρος στην περιοχή Αγαπημένα" "Εφαρμογές" diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml index 09963e422..f2a6eab16 100644 --- a/res/values-en-rAU/strings.xml +++ b/res/values-en-rAU/strings.xml @@ -32,6 +32,7 @@ "Search Apps" "Loading Apps…" "No Apps found matching \"%1$s\"" + "Go to %1$s" "No more room on this Home screen." "No more room in the Favourites tray" "Apps" diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index 09963e422..f2a6eab16 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -32,6 +32,7 @@ "Search Apps" "Loading Apps…" "No Apps found matching \"%1$s\"" + "Go to %1$s" "No more room on this Home screen." "No more room in the Favourites tray" "Apps" diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml index 09963e422..f2a6eab16 100644 --- a/res/values-en-rIN/strings.xml +++ b/res/values-en-rIN/strings.xml @@ -32,6 +32,7 @@ "Search Apps" "Loading Apps…" "No Apps found matching \"%1$s\"" + "Go to %1$s" "No more room on this Home screen." "No more room in the Favourites tray" "Apps" diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml index 636674293..c754493c8 100644 --- a/res/values-es-rUS/strings.xml +++ b/res/values-es-rUS/strings.xml @@ -32,6 +32,7 @@ "Buscar aplicaciones" "Cargando aplicaciones…" "No hay aplicaciones que coincidan con %1$s." + "Ir a %1$s" "No hay más espacio en esta pantalla principal." "La bandeja de favoritos está llena." "Aplicaciones" diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 34331fce9..16cd84fb2 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -32,6 +32,7 @@ "Busca aplicaciones" "Cargando aplicaciones…" "No se han encontrado aplicaciones que contengan \"%1$s\"" + "Ir a %1$s" "No queda espacio en la pantalla de inicio." "La bandeja de favoritos está completa" "Aplicaciones" diff --git a/res/values-et-rEE/strings.xml b/res/values-et-rEE/strings.xml index c4ba823cc..84ca45af4 100644 --- a/res/values-et-rEE/strings.xml +++ b/res/values-et-rEE/strings.xml @@ -32,6 +32,7 @@ "Otsige rakendustest" "Rakenduste laadimine ..." "Päringule „%1$s” ei vastanud ükski rakendus" + "Mine: %1$s" "Sellel avaekraanil pole enam ruumi." "Salves Lemmikud pole rohkem ruumi" "Rakendused" diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml index 8bfca6cd1..096a4f95e 100644 --- a/res/values-eu-rES/strings.xml +++ b/res/values-eu-rES/strings.xml @@ -32,6 +32,7 @@ "Bilatu aplikazioetan" "Aplikazioak kargatzen…" "Ez da aurkitu \"%1$s\" bilaketarekin bat datorren aplikaziorik" + "Joan hona: %1$s" "Hasierako pantaila honetan ez dago toki gehiago." "Ez dago toki gehiago Gogokoak erretiluan" "Aplikazioak" diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 701d59d50..3b6d01ae6 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -32,6 +32,7 @@ "جستجوی برنامه‌ها" "در حال بارگیری برنامه‌ها..." "هیچ برنامه‌ای مطابق با «%1$s» پیدا نشد" + "رفتن به %1$s" "فضای بیشتری در این صفحه اصلی موجود نیست." "فضای بیشتری در سینی موارد دلخواه وجود ندارد" "برنامه‌ها" diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml index f0766d68a..47b580e3b 100644 --- a/res/values-fi/strings.xml +++ b/res/values-fi/strings.xml @@ -32,6 +32,7 @@ "Sovellushaku" "Ladataan sovelluksia…" "”%1$s” ei palauttanut sovelluksia." + "Siirry: %1$s" "Tässä aloitusruudussa ei ole enää tilaa." "Suosikit-valikossa ei ole enää tilaa" "Sovellukset" diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml index 0c19ef268..91271f7e9 100644 --- a/res/values-fr-rCA/strings.xml +++ b/res/values-fr-rCA/strings.xml @@ -32,6 +32,7 @@ "Rechercher des applications" "Chargement des applications en cours..." "Aucune application trouvée correspondant à « %1$s »" + "Aller à « %1$s »" "Pas d\'espace libre sur l\'écran d\'accueil." "Il n\'y a plus d\'espace dans la zone des favoris" "Applications" diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 662bcf14e..856690da8 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -32,6 +32,7 @@ "Rechercher dans les applications" "Chargement des applications en cours…" "Aucune application ne correspond à la requête \"%1$s\"." + "Accéder au service %1$s" "Pas d\'espace libre sur cet écran d\'accueil." "Plus d\'espace disponible dans la zone de favoris." "Applications" diff --git a/res/values-gl-rES/strings.xml b/res/values-gl-rES/strings.xml index 6cf76a7c0..ccfe21ed1 100644 --- a/res/values-gl-rES/strings.xml +++ b/res/values-gl-rES/strings.xml @@ -32,6 +32,7 @@ "Aplicacións de busca" "Cargando aplicacións..." "Non se atoparon aplicacións que coincidan con \"%1$s\"" + "Ir a %1$s" "Non hai máis espazo nesta pantalla de inicio." "Non hai máis espazo na bandexa de favoritos" "Aplicacións" diff --git a/res/values-gu-rIN/strings.xml b/res/values-gu-rIN/strings.xml index 4a2274f1b..db056a0e8 100644 --- a/res/values-gu-rIN/strings.xml +++ b/res/values-gu-rIN/strings.xml @@ -32,6 +32,7 @@ "શોધ એપ્લિકેશનો" "એપ્લિકેશનો લોડ કરી રહ્યું છે…" "\"%1$s\" થી મેળ ખાતી કોઈ એપ્લિકેશનો મળી નથી" + "%1$s પર જાઓ" "આ હોમ સ્ક્રીન પર વધુ જગ્યા નથી." "મનપસંદ ટ્રે પર વધુ જગ્યા નથી" "એપ્લિકેશનો" diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index 6fdbf2441..7cf4f33ef 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -32,6 +32,7 @@ "ऐप्‍स खोजें" "ऐप्स लोड हो रहे हैं..." "\"%1$s\" से मिलान करने वाला कोई ऐप नहीं मिला" + "%1$s पर जाएं" "इस होम स्‍क्रीन पर स्थान शेष नहीं है." "पसंदीदा ट्रे में और स्थान नहीं है" "ऐप्लिकेशन" diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index a54a7e4b0..2679570dc 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -32,6 +32,7 @@ "Pretraži aplikacije" "Učitavanje aplikacija…" "Nema aplikacija podudarnih s upitom \"%1$s\"" + "Idite na %1$s" "Na ovom početnom zaslonu više nema mjesta." "Nema više prostora na traci Favoriti" "Aplikacije" diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index e9fc5747f..41c38b2de 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -32,6 +32,7 @@ "Alkalmazások keresése" "Alkalmazások betöltése…" "Egy alkalmazás sem található a(z) „%1$s” lekérdezésre." + "Keresse fel ezt: %1$s" "Nincs több hely ezen a kezdőképernyőn." "Nincs több hely a Kedvencek tálcán" "Alkalmazások" diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml index de4aed158..49a9d18ab 100644 --- a/res/values-hy-rAM/strings.xml +++ b/res/values-hy-rAM/strings.xml @@ -32,6 +32,7 @@ "Հավելվածների որոնում" "Հավելվածների բեռնում…" %1$s» հարցմանը համապատասխանող հավելվածներ չեն գտնվել" + "Գնալ %1$s" "Այլևս տեղ չկա այս հիմնական էկրանին:" "Ընտրյալների ցուցակում այլևս ազատ տեղ չկա" "Ծրագրեր" @@ -59,11 +60,11 @@ "Պաստառներ, վիջեթներ և կարգավորումներ" "Հարմարեցնելու համար հպեք և պահեք հետնաշերտի վրա" "ՀԱՍԿԱՆԱԼԻ Է" - "Թղթապանակը բաց է, %1$d-ից %2$d" + "Պանակը բաց է, %1$d-ից %2$d" "Հպեք՝ պանակը փակելու համար" "Հպեք՝ վերանվանումը պահելու համար" - "Թղթապանակը փակ է" - "Թղթապանակը վերանվանվեց %1$s" + "Պանակը փակ է" + "Պանակը վերանվանվեց %1$s" "Թղթապանակ՝ %1$s" "Վիջեթներ" "Պաստառներ" @@ -87,7 +88,7 @@ "Ավելացնել «%1$s» պանակին" "Տարրն ավելացվեց թղթապանակում" "Ստեղծել թղթապանակ, օգտագործելով՝ %1$s" - "Թղթապանակը ստեղծվեց" + "Պանակը ստեղծվեց" "Տեղափոխել Հիմնական էկրան" "Տեղափոխել էկրանը ձախ" "Տեղափոխել էկրանը աջ" diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml index c65254a2a..21c208056 100644 --- a/res/values-in/strings.xml +++ b/res/values-in/strings.xml @@ -32,6 +32,7 @@ "Telusuri Apps" "Memuat Aplikasi..." "Tidak ditemukan Aplikasi yang cocok dengan \"%1$s\"" + "Buka %1$s" "Tidak ada ruang lagi pada layar Utama ini." "Tidak ada ruang tersisa di baki Favorit" "Aplikasi" diff --git a/res/values-is-rIS/strings.xml b/res/values-is-rIS/strings.xml index 1d46cdc93..7422eaf58 100644 --- a/res/values-is-rIS/strings.xml +++ b/res/values-is-rIS/strings.xml @@ -32,6 +32,7 @@ "Leita í forritum" "Hleður forrit…" "Ekki fundust forrit sem samsvara „%1$s“" + "Fara í %1$s" "Ekki meira pláss á þessum heimaskjá." "Ekki meira pláss í bakka fyrir uppáhald" "Forrit" diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 02057a19c..e1e75b37f 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -32,6 +32,7 @@ "Cerca app" "Caricamento di app…" "Nessuna app trovata corrispondente a \"%1$s\"" + "Vai a %1$s" "Spazio nella schermata Home esaurito." "Spazio esaurito nella barra dei Preferiti" "App" diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml index a8039f7c1..3686abdbb 100644 --- a/res/values-iw/strings.xml +++ b/res/values-iw/strings.xml @@ -32,6 +32,7 @@ "חפש אפליקציות" "טוען אפליקציות…" "לא נמצאו אפליקציות התואמות ל-\"%1$s\"" + "עבור אל %1$s" "אין עוד מקום במסך דף הבית הזה." "אין עוד מקום במגש המועדפים" "אפליקציות" diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml index ba58d88ef..87b3fa499 100644 --- a/res/values-ja/strings.xml +++ b/res/values-ja/strings.xml @@ -32,6 +32,7 @@ "アプリを検索" "アプリを読み込んでいます…" "「%1$s」に一致するアプリは見つかりませんでした" + "%1$sにアクセス" "このホーム画面に空きスペースがありません。" "お気に入りトレイに空きスペースがありません" "アプリ" @@ -57,7 +58,7 @@ "アイコンをコピー" "初期状態にリセットする" "壁紙、ウィジェット、設定" - "カスタマイズするにはバックグラウンドを押し続けます" + "カスタマイズするには背景を押し続けます" "OK" "フォルダが開いています。%1$dx%2$dの大きさです" "タップしてフォルダを閉じます" diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml index 07030d866..46a234355 100644 --- a/res/values-ka-rGE/strings.xml +++ b/res/values-ka-rGE/strings.xml @@ -32,6 +32,8 @@ "აპების ძიება" "აპები იტვირთება..." "„%1$s“-ის თანხვედრი აპები არ მოიძებნა" + + "ამ მთავარ ეკრანზე ადგილი აღარ არის." "რჩეულების თაროზე ადგილი არ არის" "აპები" diff --git a/res/values-kk-rKZ/strings.xml b/res/values-kk-rKZ/strings.xml index e79c9ce98..cae5e5edf 100644 --- a/res/values-kk-rKZ/strings.xml +++ b/res/values-kk-rKZ/strings.xml @@ -32,6 +32,7 @@ "Қолданбаларды іздеу" "Қолданбалар жүктелуде…" %1$s» сұрауына сәйкес келетін қолданбалар жоқ" + "%1$s сұрауына өту" "Бұл Негізгі экранда орын қалмады." "Қалаулылар науасында орын қалмады" "Қолданбалар" diff --git a/res/values-km-rKH/strings.xml b/res/values-km-rKH/strings.xml index 9f7f53717..5ffbf7616 100644 --- a/res/values-km-rKH/strings.xml +++ b/res/values-km-rKH/strings.xml @@ -32,6 +32,7 @@ "ស្វែងរកកម្មវិធី" "កំពុងដំណើរការកម្មវិធី..." "គ្មានកម្មវិធីដែលត្រូវជាមួយ \"%1$s\" ទេ" + "ចូលទៅកាន់ %1$s" "គ្មាន​បន្ទប់​នៅ​លើ​អេក្រង់​ដើម​នេះ​ទៀត​ទេ។" "គ្មាន​បន្ទប់​​ក្នុង​ថាស​និយម​ប្រើ" "កម្មវិធី" diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml index 5cd8792dd..a1aab7b5c 100644 --- a/res/values-kn-rIN/strings.xml +++ b/res/values-kn-rIN/strings.xml @@ -32,6 +32,7 @@ "ಅಪ್ಲಿಕೇಷನ್‌ಗಳನ್ನು ಹುಡುಕಿ" "ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ..." "\"%1$s\" ಹೊಂದಿಕೆಯ ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಕಂಡುಬಂದಿಲ್ಲ" + "%1$s ಗೆ ಹೋಗಿ" "ಈ ಮುಖಪುಟದ ಪರದೆಯಲ್ಲಿ ಹೆಚ್ಚು ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ." "ಮೆಚ್ಚಿನವುಗಳ ಟ್ರೇನಲ್ಲಿ ಹೆಚ್ಚಿನ ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ" "ಅಪ್ಲಿಕೇಶನ್‌ಗಳು" diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index fa445acca..e0697121a 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -32,6 +32,7 @@ "앱 검색" "앱 로드 중..." "\'%1$s\'와(과) 일치하는 앱이 없습니다." + "%1$s(으)로 이동" "홈 화면에 더 이상 공간이 없습니다." "즐겨찾기 트레이에 더 이상 공간이 없습니다." "앱" diff --git a/res/values-ky-rKG/strings.xml b/res/values-ky-rKG/strings.xml index 20787489e..c530b5c9f 100644 --- a/res/values-ky-rKG/strings.xml +++ b/res/values-ky-rKG/strings.xml @@ -32,6 +32,7 @@ "Колдонмолорду издөө" "Колдонмолор жүктөлүүдө…" "\"%1$s\" дал келген колдонмолор табылган жок" + "%1$s сурамына өтүңүз" "Бул Үй экранында бош орун жок." "Тандамалдар тайпасында орун калган жок" "Колдонмолор" diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo-rLA/strings.xml index dff2612ba..005f0265f 100644 --- a/res/values-lo-rLA/strings.xml +++ b/res/values-lo-rLA/strings.xml @@ -32,6 +32,7 @@ "ຊອກຫາແອັບ" "​ກຳ​ລັງ​ໂຫລດ​ແອັບ..." "ບໍ່​ພົບ​ແອັບ​ໃດ​ທີ່​ກົງ​ກັນ \"%1$s\"" + "ໄປ​ທີ່ %1$s" "ບໍ່ມີຫ້ອງເຫຼືອໃນໜ້າຈໍຫຼັກນີ້." "ບໍ່ມີບ່ອນຫວ່າງໃນຖາດສຳລັບເກັບສິ່ງທີ່ໃຊ້ເປັນປະຈຳ" "ແອັບຯ" diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml index b5c0832dc..442874dbe 100644 --- a/res/values-lt/strings.xml +++ b/res/values-lt/strings.xml @@ -32,6 +32,7 @@ "Ieškoti programų" "Įkeliamos programos..." "Nerasta jokių užklausą „%1$s“ atitinkančių programų" + "Eiti į %1$s" "Šiame pagrindiniame ekrane vietos nebėra." "Mėgstamiausių dėkle nebėra vietos" "Programos" diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index 432bda443..1bef22e03 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -32,6 +32,7 @@ "Meklēt lietotnes" "Notiek lietotņu ielāde…" "Vaicājumam “%1$s” neatbilda neviena lietotne." + "Doties uz: %1$s" "Šajā sākuma ekrānā vairs nav vietas." "Izlases joslā vairs nav vietas." "Lietotnes" diff --git a/res/values-mk-rMK/strings.xml b/res/values-mk-rMK/strings.xml index 8c276e3f0..0a6704b50 100644 --- a/res/values-mk-rMK/strings.xml +++ b/res/values-mk-rMK/strings.xml @@ -32,6 +32,7 @@ "Пребарување апликации" "Се вчитуваат апликации…" "Не се најдени апликации што одговараат на „%1$s“" + "Оди на %1$s" "Нема повеќе простор на овој екран на почетната страница." "Нема повеќе простор на лентата „Омилени“" "Апликации" diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml-rIN/strings.xml index 59ad153a8..2bd80d358 100644 --- a/res/values-ml-rIN/strings.xml +++ b/res/values-ml-rIN/strings.xml @@ -32,6 +32,7 @@ "ആപ്പ്‌സ് തിരയുക" "ആപ്പ്‌സ് ലോഡുചെയ്യുന്നു..." "\"%1$s\" എന്നതുമായി പൊരുത്തപ്പെടുന്ന ആപ്പ്‌സൊന്നും കണ്ടെത്തിയില്ല" + "%1$s എന്നതിലേക്ക് പോവുക" "ഈ ഹോം സ്‌ക്രീനിൽ ഒഴിവൊന്നുമില്ല." "പ്രിയപ്പെട്ടവയുടെ ട്രേയിൽ ഒഴിവൊന്നുമില്ല" "അപ്ലിക്കേഷനുകൾ" diff --git a/res/values-mn-rMN/strings.xml b/res/values-mn-rMN/strings.xml index fafb37b2c..19ba66fdb 100644 --- a/res/values-mn-rMN/strings.xml +++ b/res/values-mn-rMN/strings.xml @@ -32,6 +32,7 @@ "Апп хайх" "Аппликейшныг ачаалж байна..." "\"%1$s\"-тай нийцэх апп олдсонгүй" + "%1$s руу очих" "Энэ Нүүр дэлгэц зайгүй." "\"Дуртай\" трей дээр өөр зай байхгүй байна" "Апп" diff --git a/res/values-mr-rIN/strings.xml b/res/values-mr-rIN/strings.xml index 657010d6c..dc29b5462 100644 --- a/res/values-mr-rIN/strings.xml +++ b/res/values-mr-rIN/strings.xml @@ -32,6 +32,7 @@ "अॅप्स शोधा" "अॅप्स लोड करीत आहे..." "\"%1$s\" शी जुळणारे कोणतेही अॅप्स आढळले नाहीत" + "%1$s वर जा" "या मुख्य स्क्रीनवर आणखी जागा नाही." "आवडीच्या ट्रे मध्ये आणखी जागा नाही" "अॅप्स" diff --git a/res/values-ms-rMY/strings.xml b/res/values-ms-rMY/strings.xml index 0c6a5f501..26f27488c 100644 --- a/res/values-ms-rMY/strings.xml +++ b/res/values-ms-rMY/strings.xml @@ -32,6 +32,7 @@ "Cari Apl" "Memuatkan Apl…" "Tiada Apl yang ditemui sepadan dengan \"%1$s\"" + "Pergi ke %1$s" "Tiada lagi ruang pada skrin Laman Utama ini." "Tiada ruang dalam dulang Kegemaran lagi" "Apl" diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml index 19ec3a6ff..c13ff7e0d 100644 --- a/res/values-my-rMM/strings.xml +++ b/res/values-my-rMM/strings.xml @@ -32,6 +32,7 @@ "ရှာဖွေမှု Appများ" "App များ ရယူနေစဉ်..." "\"%1$s\" နှင့်ကိုက်ညီသည့် အပ်ဖ်များမတွေ့ပါ" + "%1$sကို သွားပါ" "ဤပင်မမျက်နှာစာတွင် နေရာလွတ် မကျန်တော့ပါ" "အနှစ်သက်ဆုံးများ ထားရာတွင် နေရာလွတ် မကျန်တော့ပါ" "အပ်ပလီကေးရှင်းများ" diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml index 21b87c894..198d56c21 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -32,6 +32,7 @@ "Søk i apper" "Laster inn apper …" "Fant ingen apper som samsvarer med «%1$s»" + "Gå til %1$s" "Denne startsiden er full." "Favoritter-skuffen er full" "Apper" diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne-rNP/strings.xml index dd3b3f310..472bd4f5d 100644 --- a/res/values-ne-rNP/strings.xml +++ b/res/values-ne-rNP/strings.xml @@ -32,6 +32,7 @@ "अनुप्रयोगहरू खोज्नुहोस्" "अनुप्रयोगहरू लोड गरिँदै..." "\"%1$s\" सँग मिल्दो कुनै अनुप्रयोगहरू फेला परेनन्" + "%1$s मा जानुहोस्" "यो गृह स्क्रिनमा कुनै थप ठाउँ छैन।" "मनपर्ने ट्रे अब कुनै ठाँउ छैन" "अनुप्रयोगहरू" diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml index fcbe375e7..6f4981087 100644 --- a/res/values-nl/strings.xml +++ b/res/values-nl/strings.xml @@ -32,6 +32,7 @@ "Apps zoeken" "Apps laden…" "Er zijn geen apps gevonden die overeenkomen met \'%1$s\'" + "Ga naar %1$s" "Er is geen ruimte meer op dit startscherm." "Geen ruimte meer in het vak \'Favorieten\'" "Apps" diff --git a/res/values-pa-rIN/strings.xml b/res/values-pa-rIN/strings.xml index d510dc7fa..30c44280e 100644 --- a/res/values-pa-rIN/strings.xml +++ b/res/values-pa-rIN/strings.xml @@ -32,6 +32,7 @@ "ਐਪਸ ਖੋਜੋ" "ਐਪਸ ਲੋਡ ਕਰ ਰਿਹਾ ਹੈ..." "\"%1$s\" ਨਾਲ ਮਿਲਦੀ ਕੋਈ ਵੀ ਐਪਸ ਨਹੀਂ ਲੱਭੀਆਂ" + "%1$s ਤੇ ਜਾਓ" "ਇਸ ਹੋਮ ਸਕ੍ਰੀਨ ਲਈ ਹੋਰ ਖਾਲੀ ਸਥਾਨ ਨਹੀਂ ਹੈ।" "ਮਨਪਸੰਦ ਟ੍ਰੇ ਵਿੱਚ ਹੋਰ ਖਾਲੀ ਸਥਾਨ ਨਹੀਂ।" "ਐਪਸ" diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index b3b761d9c..a1fd29f56 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -32,6 +32,7 @@ "Szukaj w aplikacjach" "Wczytuję aplikacje…" "Nie znaleziono aplikacji pasujących do zapytania „%1$s”" + "Otwórz %1$s" "Brak miejsca na tym ekranie głównym." "Brak miejsca w Ulubionych" "Aplikacje" diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml index 9140b62f2..0d8a43179 100644 --- a/res/values-pt-rPT/strings.xml +++ b/res/values-pt-rPT/strings.xml @@ -32,6 +32,7 @@ "Pesquisar aplicações" "A carregar aplicações..." "Não foram encontradas aplic. que correspondam a \"%1$s\"" + "Aceder a %1$s" "Sem espaço suficiente neste Ecrã principal." "Não existe mais espaço no tabuleiro de Favoritos" "Aplicações" diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index c8e645849..41e5c021e 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -32,6 +32,7 @@ "Pesquisar apps" "Carregando apps…" "Nenhum app encontrado que corresponda a \"%1$s\"" + "Ir para %1$s" "Não há mais espaço na tela inicial." "Sem espaço na bandeja de favoritos" "Apps" diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index 88cbc79fc..ffaca7856 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -32,6 +32,7 @@ "Căutați aplicații" "Se încarcă aplicațiile..." "Nu s-a găsit nicio aplicație pentru „%1$s”" + "Accesați %1$s" "Nu mai este loc pe acest Ecran de pornire." "Spațiu epuizat în bara Preferate" "Aplicații" diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 5b492fe12..6e69e4dee 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -32,6 +32,7 @@ "Поиск приложений" "Загрузка…" "По запросу \"%1$s\" ничего не найдено" + "%1$s" "На этом экране все занято" "В разделе \"Избранное\" больше нет места" "Приложения" diff --git a/res/values-si-rLK/strings.xml b/res/values-si-rLK/strings.xml index 68e3178ae..476fff816 100644 --- a/res/values-si-rLK/strings.xml +++ b/res/values-si-rLK/strings.xml @@ -32,6 +32,7 @@ "යෙදුම් සෙවීම" "යෙදුම් පූරණය වෙමින්…" "\"%1$s\" සමග ගැළපෙන යෙදුම් හමු නොවිණි" + "%1$s වෙත යන්න" "මෙම මුල් පිටු තිරය මත තවත් අවසර නැත." "ප්‍රියතම දෑ ඇති තැටියේ තවත් ඉඩ නොමැත" "යෙදුම්" diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml index 1cb76e3a8..703b46cb4 100644 --- a/res/values-sk/strings.xml +++ b/res/values-sk/strings.xml @@ -32,6 +32,7 @@ "Vyhľadávanie v aplikáciách" "Načítavajú sa aplikácie..." "Nenašli sa žiadne aplikácie zodpovedajúce dopytu %1$s" + "Prejsť na dopyt %1$s" "Na tejto ploche už nie je miesto" "Na paneli Obľúbené položky už nie je miesto" "Aplikácie" diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml index 92c69a562..497378b78 100644 --- a/res/values-sl/strings.xml +++ b/res/values-sl/strings.xml @@ -32,6 +32,7 @@ "Iskanje po aplikacijah" "Nalaganje aplikacij …" "Ni aplikacij, ki bi ustrezale poizvedbi »%1$s«" + "Odpri storitev %1$s" "Na tem začetnem zaslonu ni več prostora." "V vrstici za priljubljene ni več prostora" "Aplikacije" diff --git a/res/values-sq-rAL/strings.xml b/res/values-sq-rAL/strings.xml index 65aabf689..2b535a3a5 100644 --- a/res/values-sq-rAL/strings.xml +++ b/res/values-sq-rAL/strings.xml @@ -32,6 +32,7 @@ "Kërko për aplikacione" "Po ngarkon aplikacionet..." "Nuk u gjet asnjë aplikacion që përputhet me \"%1$s\"" + "Shko te %1$s" "Nuk ka më hapësirë në këtë ekran bazë." "Nuk ka më hapësirë në tabakanë \"Të preferuarat\"" "Aplikacionet" diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml index 0f93bf3ea..f21aae019 100644 --- a/res/values-sr/strings.xml +++ b/res/values-sr/strings.xml @@ -32,6 +32,7 @@ "Претражите апликације" "Апликације се учитавају..." "Није пронађена ниједна апликација за „%1$s“" + "Иди на апликацију %1$s" "Нема више простора на овом почетном екрану." "Нема више простора на траци Омиљено" "Апликације" diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml index 93fce80ca..385d7a6f6 100644 --- a/res/values-sv/strings.xml +++ b/res/values-sv/strings.xml @@ -32,6 +32,7 @@ "Sök efter appar" "Läser in appar …" "Det gick inte att hitta några appar som matchar %1$s" + "Gå till %1$s" "Det finns inte plats för mer på den här startskärmen." "Favoritfältet är fullt" "Appar" diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml index 297b731bf..b86fb7325 100644 --- a/res/values-sw/strings.xml +++ b/res/values-sw/strings.xml @@ -32,6 +32,7 @@ "Tafuta Programu" "Inapakia Programu..." "Haikupata programu zinazolingana na \"%1$s\"" + "Nenda kwenye %1$s" "Hakuna nafasi katika skrini hii ya Mwanzo." "Hakuna nafasi zaidi katika treya ya Vipendeleo" "Programu" diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml index 1f2a6f959..9dac6d011 100644 --- a/res/values-ta-rIN/strings.xml +++ b/res/values-ta-rIN/strings.xml @@ -32,6 +32,7 @@ "பயன்பாடுகளில் தேடுக" "பயன்பாடுகளை ஏற்றுகிறது..." "\"%1$s\" உடன் பொருந்தும் பயன்பாடுகள் இல்லை" + "%1$sக்குச் செல்லவும்" "முகப்புத் திரையில் இடமில்லை." "பிடித்தவை ட்ரேயில் இடமில்லை" "பயன்பாடுகள்" diff --git a/res/values-te-rIN/strings.xml b/res/values-te-rIN/strings.xml index bd5fd70db..32cb292a1 100644 --- a/res/values-te-rIN/strings.xml +++ b/res/values-te-rIN/strings.xml @@ -32,6 +32,7 @@ "అనువర్తనాలను శోధించండి" "అనువర్తనాలను లోడ్ చేస్తోంది…" "\"%1$s\"కి సరిపోలే అనువర్తనాలేవీ కనుగొనబడలేదు" + "%1$sకి వెళ్లు" "ఈ హోమ్ స్క్రీన్‌లో ఖాళీ లేదు." "ఇష్టమైనవి ట్రేలో ఖాళీ లేదు" "అనువర్తనాలు" diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml index 85919af9a..53ae5896b 100644 --- a/res/values-th/strings.xml +++ b/res/values-th/strings.xml @@ -32,6 +32,7 @@ "ค้นหาแอป" "กำลังโหลดแอป…" "ไม่พบแอปที่ตรงกับ \"%1$s\"" + "ไปที่ %1$s" "ไม่มีที่ว่างในหน้าจอหลักนี้" "ไม่มีพื้นที่เหลือในถาดรายการโปรด" "แอป" diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml index 69a5bb7d9..43afeab53 100644 --- a/res/values-tl/strings.xml +++ b/res/values-tl/strings.xml @@ -32,6 +32,7 @@ "Mga App sa Paghahanap" "Nilo-load ang Mga App…" "Walang nakitang Mga App na tumutugma sa \"%1$s\"" + "Pumunta sa %1$s" "Wala nang lugar sa Home screen na ito." "Wala nang lugar sa tray ng Mga Paborito" "Apps" diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index d933c8770..064d0496a 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -32,6 +32,7 @@ "Uygulamalarda Ara" "Uygulamalar Yükleniyor…" "\"%1$s\" ile eşleşen uygulama bulunamadı" + "%1$s uygulamasına git" "Bu Ana ekranda yer kalmadı." "Favoriler tepsisinde başka yer kalmadı" "Uygulamalar" diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index b06177e71..ff9364e5f 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -32,6 +32,7 @@ "Пошук додатків" "Завантаження додатків…" "Немає додатків для запиту \"%1$s\"" + "Перейти в додаток %1$s" "На цьому головному екрані більше немає місця." "В області \"Вибране\" немає місця" "Додатки" diff --git a/res/values-ur-rPK/strings.xml b/res/values-ur-rPK/strings.xml index ba189c87d..f3d631173 100644 --- a/res/values-ur-rPK/strings.xml +++ b/res/values-ur-rPK/strings.xml @@ -32,6 +32,7 @@ "ایپس تلاش کریں" "ایپس لوڈ ہو رہی ہیں…" "\"%1$s\" سے مماثل کوئی ایپس نہیں ملیں" + "%1$s پر جائیں" "اس ہوم اسکرین پر مزید کوئی گنجائش نہیں ہے۔" "پسندیدہ ٹرے میں مزید کوئی گنجائش نہیں ہے" "ایپس" diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz-rUZ/strings.xml index c3bffeb3c..24e4c4d14 100644 --- a/res/values-uz-rUZ/strings.xml +++ b/res/values-uz-rUZ/strings.xml @@ -32,6 +32,7 @@ "Ilovalarni qidirish" "Ilovalar yuklanmoqda…" "“%1$s” bilan mos hech qanday ilova topilmadi" + "O‘tish: %1$s" "Uy ekranida bitta ham xona yo‘q." "Ajratilganlarda birorta ham xona yo‘q" "Ilovalar" diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index f57f491ae..6eff50760 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -32,6 +32,7 @@ "Tìm kiếm ứng dụng" "Đang tải ứng dụng..." "Không tìm thấy ứng dụng nào phù hợp với \"%1$s\"" + "Chuyển tới %1$s" "Không còn chỗ trên Màn hình chính này." "Không còn chỗ trong khay Mục yêu thích" "Ứng dụng" diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 82274ba2c..495a14b37 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -32,6 +32,8 @@ "搜索应用" "正在加载应用…" "未找到与“%1$s”相符的应用" + + "此主屏幕上已没有空间。" "收藏栏已满" "应用" diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml index f7d240e05..62032ecaa 100644 --- a/res/values-zh-rHK/strings.xml +++ b/res/values-zh-rHK/strings.xml @@ -32,6 +32,7 @@ "搜尋應用程式" "正在載入應用程式…" "無法找到與「%1$s」相符的應用程式" + "前往 %1$s" "主畫面已無空間。" "我的收藏寄存區沒有足夠空間" "應用程式" diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 39a0ec77a..0b3f4d6bc 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -32,6 +32,7 @@ "搜尋應用程式" "正在載入應用程式…" "找不到符合「%1$s」的應用程式" + "前往 %1$s" "這個主螢幕已無空間。" "「我的最愛」匣已無可用空間" "應用程式" diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml index 83ba089df..bb49f1f0a 100644 --- a/res/values-zu/strings.xml +++ b/res/values-zu/strings.xml @@ -32,6 +32,7 @@ "Sesha Izinhlelo Zokusebenza" "Ilayisha izinhlelo zokusebenza..." "Azikho izinhlelo zokusebenza ezitholakele ezifana ne-\"%1$s\"" + "Hamba ku-%1$s" "Asisekho isikhala kulesi sikrini Sasekhaya." "Asisekho isikhala kwitreyi lezintandokazi" "Izinhlelo zokusebenza" -- cgit v1.2.3 From 79a640ec354e61363e0c347793f70b3a285a0240 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 12 Aug 2015 15:28:33 -0700 Subject: Ensure that crop view is loaded before applying a wallpaper Bug: 22293299 Change-Id: I64d5268cc263bbb6595a0b28bdd5ec73d540da41 --- WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java index 069638f8c..75d874552 100644 --- a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java +++ b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java @@ -550,7 +550,8 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { new View.OnClickListener() { @Override public void onClick(View v) { - if (mSelectedTile != null) { + // Ensure that a tile is slelected and loaded. + if (mSelectedTile != null && mCropView.getTileSource() != null) { // Prevent user from selecting any new tile. mWallpaperStrip.setVisibility(View.GONE); actionBar.hide(); -- cgit v1.2.3 From d106418dee16b041f30682540fbd3ca3d841b7af Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 13 Aug 2015 12:08:30 -0700 Subject: Reloading launcher whenever there is an external update to contentprovider, irrespective of the uri Change-Id: If1a06da57171be30adb74f09ac256a8b03ab8549 --- src/com/android/launcher3/LauncherProvider.java | 29 ++++++++++++++----------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index 6cbb267be..059971405 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -77,8 +77,6 @@ public class LauncherProvider extends ContentProvider { static final String TABLE_WORKSPACE_SCREENS = LauncherSettings.WorkspaceScreens.TABLE_NAME; static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED"; - private static final String URI_PARAM_IS_EXTERNAL_ADD = "isExternalAdd"; - private static final String RESTRICTION_PACKAGE_NAME = "workspace.configuration.package.name"; @Thunk LauncherProviderChangeListener mListener; @@ -140,14 +138,21 @@ public class LauncherProvider extends ContentProvider { return db.insert(table, nullColumnHack, values); } + private void reloadLauncherIfExternal() { + if (Binder.getCallingPid() != Process.myPid()) { + LauncherAppState app = LauncherAppState.getInstanceNoCreate(); + if (app != null) { + app.reloadWorkspace(); + } + } + } + @Override public Uri insert(Uri uri, ContentValues initialValues) { SqlArguments args = new SqlArguments(uri); - // In very limited cases, we support system|signature permission apps to add to the db - String externalAdd = uri.getQueryParameter(URI_PARAM_IS_EXTERNAL_ADD); - final boolean isExternalAll = externalAdd != null && "true".equals(externalAdd); - if (isExternalAll) { + // In very limited cases, we support system|signature permission apps to modify the db. + if (Binder.getCallingPid() != Process.myPid()) { if (!mOpenHelper.initializeExternalAdd(initialValues)) { return null; } @@ -161,13 +166,7 @@ public class LauncherProvider extends ContentProvider { uri = ContentUris.withAppendedId(uri, rowId); notifyListeners(); - if (isExternalAll) { - LauncherAppState app = LauncherAppState.getInstanceNoCreate(); - if (app != null) { - app.reloadWorkspace(); - } - } - + reloadLauncherIfExternal(); return uri; } @@ -192,6 +191,7 @@ public class LauncherProvider extends ContentProvider { } notifyListeners(); + reloadLauncherIfExternal(); return values.length; } @@ -203,6 +203,7 @@ public class LauncherProvider extends ContentProvider { try { ContentProviderResult[] result = super.applyBatch(operations); db.setTransactionSuccessful(); + reloadLauncherIfExternal(); return result; } finally { db.endTransaction(); @@ -217,6 +218,7 @@ public class LauncherProvider extends ContentProvider { int count = db.delete(args.table, args.where, args.args); if (count > 0) notifyListeners(); + reloadLauncherIfExternal(); return count; } @@ -229,6 +231,7 @@ public class LauncherProvider extends ContentProvider { int count = db.update(args.table, values, args.where, args.args); if (count > 0) notifyListeners(); + reloadLauncherIfExternal(); return count; } -- cgit v1.2.3 From 97b0d08d92c64034ba03ae8da5a8531edbd60d52 Mon Sep 17 00:00:00 2001 From: Winson Date: Thu, 13 Aug 2015 15:18:25 -0700 Subject: Refactoring to ExtendedEditText. --- res/layout/all_apps_search_bar.xml | 2 +- res/layout/user_folder.xml | 2 +- src/com/android/launcher3/ExtendedEditText.java | 65 ++++++++++++++++++++++ src/com/android/launcher3/Folder.java | 13 ++++- src/com/android/launcher3/FolderEditText.java | 36 ------------ .../launcher3/allapps/AllAppsSearchEditView.java | 65 ---------------------- .../allapps/DefaultAppSearchController.java | 12 ++-- 7 files changed, 85 insertions(+), 110 deletions(-) create mode 100644 src/com/android/launcher3/ExtendedEditText.java delete mode 100644 src/com/android/launcher3/FolderEditText.java delete mode 100644 src/com/android/launcher3/allapps/AllAppsSearchEditView.java diff --git a/res/layout/all_apps_search_bar.xml b/res/layout/all_apps_search_bar.xml index 0c183eaee..69a66c817 100644 --- a/res/layout/all_apps_search_bar.xml +++ b/res/layout/all_apps_search_bar.xml @@ -38,7 +38,7 @@ android:contentDescription="@string/all_apps_button_label" android:src="@drawable/ic_arrow_back_grey" /> - - Date: Wed, 12 Aug 2015 15:12:16 -0700 Subject: Disabling auto restore of widgets. > Always show "Setup" button for a widget which has a config activity. Bug: 23155863 Change-Id: I60683889e76be830a76ac1245e079574aaf0ad10 --- .../launcher3/AppWidgetsRestoredReceiver.java | 4 +- src/com/android/launcher3/Launcher.java | 74 ++++++++++++---------- src/com/android/launcher3/LauncherModel.java | 8 ++- 3 files changed, 52 insertions(+), 34 deletions(-) diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java index 5e7a012d2..b1d51ece0 100644 --- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java +++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java @@ -13,6 +13,7 @@ import android.os.AsyncTask; import android.util.Log; import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.compat.AppWidgetManagerCompat; import java.util.ArrayList; import java.util.List; @@ -48,7 +49,8 @@ public class AppWidgetsRestoredReceiver extends BroadcastReceiver { final AppWidgetProviderInfo provider = widgets.getAppWidgetInfo(newWidgetIds[i]); final int state; if (LauncherModel.isValidProvider(provider)) { - state = LauncherAppWidgetInfo.RESTORE_COMPLETED; + // This will ensure that we show 'Click to setup' UI if required. + state = LauncherAppWidgetInfo.FLAG_UI_NOT_READY; } else { state = LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY; } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 298b2c469..19ddeec4a 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -3889,7 +3889,8 @@ public class Launcher extends Activity if (!mIsSafeModeEnabled && ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY) == 0) - && ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) != 0)) { + && (item.restoreStatus != LauncherAppWidgetInfo.RESTORE_COMPLETED)) { + if (appWidgetInfo == null) { if (DEBUG_WIDGETS) { Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId @@ -3899,42 +3900,51 @@ public class Launcher extends Activity LauncherModel.deleteItemFromDatabase(this, item); return; } - // Note: This assumes that the id remap broadcast is received before this step. - // If that is not the case, the id remap will be ignored and user may see the - // click to setup view. - PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(this, appWidgetInfo, null); - pendingInfo.spanX = item.spanX; - pendingInfo.spanY = item.spanY; - pendingInfo.minSpanX = item.minSpanX; - pendingInfo.minSpanY = item.minSpanY; - Bundle options = null; - WidgetHostViewLoader.getDefaultOptionsForWidget(this, pendingInfo); - - int newWidgetId = mAppWidgetHost.allocateAppWidgetId(); - boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed( - newWidgetId, appWidgetInfo, options); - // TODO consider showing a permission dialog when the widget is clicked. - if (!success) { - mAppWidgetHost.deleteAppWidgetId(newWidgetId); - if (DEBUG_WIDGETS) { - Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId - + " belongs to component " + item.providerName - + ", as the launcher is unable to bing a new widget id"); + // If we do not have a valid id, try to bind an id. + if ((item.restoreStatus & LauncherAppWidgetInfo.FLAG_ID_NOT_VALID) != 0) { + // Note: This assumes that the id remap broadcast is received before this step. + // If that is not the case, the id remap will be ignored and user may see the + // click to setup view. + PendingAddWidgetInfo pendingInfo = new PendingAddWidgetInfo(this, appWidgetInfo, null); + pendingInfo.spanX = item.spanX; + pendingInfo.spanY = item.spanY; + pendingInfo.minSpanX = item.minSpanX; + pendingInfo.minSpanY = item.minSpanY; + Bundle options = null; + WidgetHostViewLoader.getDefaultOptionsForWidget(this, pendingInfo); + + int newWidgetId = mAppWidgetHost.allocateAppWidgetId(); + boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed( + newWidgetId, appWidgetInfo, options); + + // TODO consider showing a permission dialog when the widget is clicked. + if (!success) { + mAppWidgetHost.deleteAppWidgetId(newWidgetId); + if (DEBUG_WIDGETS) { + Log.d(TAG, "Removing restored widget: id=" + item.appWidgetId + + " belongs to component " + item.providerName + + ", as the launcher is unable to bing a new widget id"); + } + LauncherModel.deleteItemFromDatabase(this, item); + return; } - LauncherModel.deleteItemFromDatabase(this, item); - return; - } - item.appWidgetId = newWidgetId; + item.appWidgetId = newWidgetId; - // If the widget has a configure activity, it is still needs to set it up, otherwise - // the widget is ready to go. - item.restoreStatus = (appWidgetInfo.configure == null) - ? LauncherAppWidgetInfo.RESTORE_COMPLETED - : LauncherAppWidgetInfo.FLAG_UI_NOT_READY; + // If the widget has a configure activity, it is still needs to set it up, otherwise + // the widget is ready to go. + item.restoreStatus = (appWidgetInfo.configure == null) + ? LauncherAppWidgetInfo.RESTORE_COMPLETED + : LauncherAppWidgetInfo.FLAG_UI_NOT_READY; - LauncherModel.updateItemInDatabase(this, item); + LauncherModel.updateItemInDatabase(this, item); + } else if (((item.restoreStatus & LauncherAppWidgetInfo.FLAG_UI_NOT_READY) != 0) + && (appWidgetInfo.configure == null)) { + // If the ID is already valid, verify if we need to configure or not. + item.restoreStatus = LauncherAppWidgetInfo.RESTORE_COMPLETED; + LauncherModel.updateItemInDatabase(this, item); + } } if (!mIsSafeModeEnabled && item.restoreStatus == LauncherAppWidgetInfo.RESTORE_COMPLETED) { diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index d9b0cd490..6dfb4d93e 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -2194,7 +2194,7 @@ public class LauncherModel extends BroadcastReceiver // Id would be valid only if the widget restore broadcast was received. if (isIdValid) { - status = LauncherAppWidgetInfo.RESTORE_COMPLETED; + status = LauncherAppWidgetInfo.FLAG_UI_NOT_READY; } else { status &= ~LauncherAppWidgetInfo .FLAG_PROVIDER_NOT_READY; @@ -3197,6 +3197,12 @@ public class LauncherModel extends BroadcastReceiver widgetInfo.restoreStatus &= ~LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY & ~LauncherAppWidgetInfo.FLAG_RESTORE_STARTED; + + // adding this flag ensures that launcher shows 'click to setup' + // if the widget has a config activity. In case there is no config + // activity, it will be marked as 'restored' during bind. + widgetInfo.restoreStatus |= LauncherAppWidgetInfo.FLAG_UI_NOT_READY; + widgets.add(widgetInfo); updateItemInDatabase(context, widgetInfo); } -- cgit v1.2.3 From 13da3efb7ad2100f8d1263fa8f13a21691b86501 Mon Sep 17 00:00:00 2001 From: Geoff Mendal Date: Mon, 17 Aug 2015 07:09:24 -0700 Subject: Import translations. DO NOT MERGE Change-Id: Iedffa6e0a67907f0d86dfaf9b9863c4580cc3cf5 Auto-generated-cl: translation import --- res/values-fr/strings.xml | 2 +- res/values-ka-rGE/strings.xml | 3 +-- res/values-zh-rCN/strings.xml | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 856690da8..84e1594b4 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -32,7 +32,7 @@ "Rechercher dans les applications" "Chargement des applications en cours…" "Aucune application ne correspond à la requête \"%1$s\"." - "Accéder au service %1$s" + "Accéder à %1$s" "Pas d\'espace libre sur cet écran d\'accueil." "Plus d\'espace disponible dans la zone de favoris." "Applications" diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml index 46a234355..290033088 100644 --- a/res/values-ka-rGE/strings.xml +++ b/res/values-ka-rGE/strings.xml @@ -32,8 +32,7 @@ "აპების ძიება" "აპები იტვირთება..." "„%1$s“-ის თანხვედრი აპები არ მოიძებნა" - - + "გადადი %1$s-ში" "ამ მთავარ ეკრანზე ადგილი აღარ არის." "რჩეულების თაროზე ადგილი არ არის" "აპები" diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 495a14b37..77f07c955 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -32,8 +32,7 @@ "搜索应用" "正在加载应用…" "未找到与“%1$s”相符的应用" - - + "转到 %1$s" "此主屏幕上已没有空间。" "收藏栏已满" "应用" -- cgit v1.2.3 From ac36643be1fc6f7ef47090db73156bc4e57c68cc Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 14 Aug 2015 17:10:14 -0700 Subject: Updating the UI for the pending widget view Bug: 23183034 Change-Id: I2b3f6f765a51edf75e666186650bbd3cf7b66a7a --- res/values/dimens.xml | 4 + .../launcher3/PendingAppWidgetHostView.java | 200 +++++++++++++-------- 2 files changed, 125 insertions(+), 79 deletions(-) diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 589d69666..b9fb6e257 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -129,4 +129,8 @@ 4dp 2dp + + 8dp + 2dp + diff --git a/src/com/android/launcher3/PendingAppWidgetHostView.java b/src/com/android/launcher3/PendingAppWidgetHostView.java index 08f8e5601..e8c8b8ec9 100644 --- a/src/com/android/launcher3/PendingAppWidgetHostView.java +++ b/src/com/android/launcher3/PendingAppWidgetHostView.java @@ -16,13 +16,17 @@ package com.android.launcher3; +import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.content.res.Resources.Theme; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.Bundle; import android.text.Layout; import android.text.StaticLayout; @@ -32,6 +36,8 @@ import android.view.View; import android.view.View.OnClickListener; public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implements OnClickListener { + private static final float SETUP_ICON_SIZE_FACTOR = 2f / 5; + private static final float MIN_SATUNATION = 0.7f; private static Theme sPreloaderTheme; @@ -47,13 +53,14 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen private Bitmap mIcon; private Drawable mCenterDrawable; - private Drawable mTopCornerDrawable; + private Drawable mSettingIconDrawable; private boolean mDrawableSizeChanged; private final TextPaint mPaint; private Layout mSetupTextLayout; + @TargetApi(Build.VERSION_CODES.LOLLIPOP) public PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info, boolean disabledForSafeMode) { super(context); @@ -70,6 +77,10 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen mLauncher.getDeviceProfile().iconTextSizePx, getResources().getDisplayMetrics())); setBackgroundResource(R.drawable.quantum_panel_dark); setWillNotDraw(false); + + if (Utilities.isLmpOrAbove()) { + setElevation(getResources().getDimension(R.dimen.pending_widget_elevation)); + } } @Override @@ -124,10 +135,12 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen FastBitmapDrawable disabledIcon = mLauncher.createIconDrawable(mIcon); disabledIcon.setGhostModeEnabled(true); mCenterDrawable = disabledIcon; - mTopCornerDrawable = null; + mSettingIconDrawable = null; } else if (isReadyForClickSetup()) { - mCenterDrawable = getResources().getDrawable(R.drawable.ic_setting); - mTopCornerDrawable = new FastBitmapDrawable(mIcon); + mCenterDrawable = new FastBitmapDrawable(mIcon); + mSettingIconDrawable = getResources().getDrawable(R.drawable.ic_setting).mutate(); + + updateSettingColor(); } else { if (sPreloaderTheme == null) { sPreloaderTheme = getResources().newTheme(); @@ -137,13 +150,25 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen FastBitmapDrawable drawable = mLauncher.createIconDrawable(mIcon); mCenterDrawable = new PreloadIconDrawable(drawable, sPreloaderTheme); mCenterDrawable.setCallback(this); - mTopCornerDrawable = null; + mSettingIconDrawable = null; applyState(); } mDrawableSizeChanged = true; } } + private void updateSettingColor() { + int color = Utilities.findDominantColorByHue(mIcon, 20); + // Make the dominant color bright. + float[] hsv = new float[3]; + Color.colorToHSV(color, hsv); + hsv[1] = Math.min(hsv[1], MIN_SATUNATION); + hsv[2] = 1; + color = Color.HSVToColor(hsv); + + mSettingIconDrawable.setColorFilter(color, PorterDuff.Mode.SRC_IN); + } + @Override protected boolean verifyDrawable(Drawable who) { return (who == mCenterDrawable) || super.verifyDrawable(who); @@ -169,6 +194,83 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen && (mInfo.restoreStatus & LauncherAppWidgetInfo.FLAG_UI_NOT_READY) != 0; } + private void updateDrawableBounds() { + DeviceProfile grid = mLauncher.getDeviceProfile(); + int paddingTop = getPaddingTop(); + int paddingBottom = getPaddingBottom(); + int paddingLeft = getPaddingLeft(); + int paddingRight = getPaddingRight(); + + int minPadding = getResources() + .getDimensionPixelSize(R.dimen.pending_widget_min_padding); + + int availableWidth = getWidth() - paddingLeft - paddingRight - 2 * minPadding; + int availableHeight = getHeight() - paddingTop - paddingBottom - 2 * minPadding; + + if (mSettingIconDrawable == null) { + int outset = (mCenterDrawable instanceof PreloadIconDrawable) ? + ((PreloadIconDrawable) mCenterDrawable).getOutset() : 0; + int maxSize = grid.iconSizePx + 2 * outset; + int size = Math.min(maxSize, Math.min(availableWidth, availableHeight)); + + mRect.set(0, 0, size, size); + mRect.inset(outset, outset); + mRect.offsetTo((getWidth() - mRect.width()) / 2, (getHeight() - mRect.height()) / 2); + mCenterDrawable.setBounds(mRect); + } else { + float iconSize = Math.min(availableWidth, availableHeight); + + // Use twice the setting size factor, as the setting is drawn at a corner and the + // icon is drawn in the center. + float settingIconScaleFactor = 1 + SETUP_ICON_SIZE_FACTOR * 2; + int maxSize = Math.max(availableWidth, availableHeight); + if (iconSize * settingIconScaleFactor > maxSize) { + // There is an overlap + iconSize = maxSize / settingIconScaleFactor; + } + + int actualIconSize = (int) Math.min(iconSize, grid.iconSizePx); + + // Recreate the setup text. + mSetupTextLayout = new StaticLayout( + getResources().getText(R.string.gadget_setup_text), mPaint, availableWidth, + Layout.Alignment.ALIGN_CENTER, 1, 0, true); + int textHeight = mSetupTextLayout.getHeight(); + + // Extra icon size due to the setting icon + float minHeightWithText = textHeight + actualIconSize * settingIconScaleFactor + + grid.iconDrawablePaddingPx; + + int iconTop; + if (minHeightWithText < availableHeight) { + // We can draw the text as well + iconTop = (getHeight() - textHeight - + grid.iconDrawablePaddingPx - actualIconSize) / 2; + + } else { + // The text will not fit. Only draw the icons. + iconTop = (getHeight() - actualIconSize) / 2; + mSetupTextLayout = null; + } + + mRect.set(0, 0, actualIconSize, actualIconSize); + mRect.offset((getWidth() - actualIconSize) / 2, iconTop); + mCenterDrawable.setBounds(mRect); + + mRect.left = paddingLeft + minPadding; + mRect.right = mRect.left + (int) (SETUP_ICON_SIZE_FACTOR * actualIconSize); + mRect.top = paddingTop + minPadding; + mRect.bottom = mRect.top + (int) (SETUP_ICON_SIZE_FACTOR * actualIconSize); + mSettingIconDrawable.setBounds(mRect); + + if (mSetupTextLayout != null) { + // Set up position for dragging the text + mRect.left = paddingLeft + minPadding; + mRect.top = mCenterDrawable.getBounds().bottom + grid.iconDrawablePaddingPx; + } + } + } + @Override protected void onDraw(Canvas canvas) { if (mCenterDrawable == null) { @@ -176,81 +278,21 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen return; } - DeviceProfile grid = mLauncher.getDeviceProfile(); - if (mTopCornerDrawable == null) { - if (mDrawableSizeChanged) { - int outset = (mCenterDrawable instanceof PreloadIconDrawable) ? - ((PreloadIconDrawable) mCenterDrawable).getOutset() : 0; - int maxSize = grid.iconSizePx + 2 * outset; - int size = Math.min(maxSize, Math.min( - getWidth() - getPaddingLeft() - getPaddingRight(), - getHeight() - getPaddingTop() - getPaddingBottom())); - - mRect.set(0, 0, size, size); - mRect.inset(outset, outset); - mRect.offsetTo((getWidth() - mRect.width()) / 2, (getHeight() - mRect.height()) / 2); - mCenterDrawable.setBounds(mRect); - mDrawableSizeChanged = false; - } - mCenterDrawable.draw(canvas); - } else { - // Draw the top corner icon and "Setup" text is possible - if (mDrawableSizeChanged) { - int iconSize = grid.iconSizePx; - int paddingTop = getPaddingTop(); - int paddingBottom = getPaddingBottom(); - int paddingLeft = getPaddingLeft(); - int paddingRight = getPaddingRight(); - - int availableWidth = getWidth() - paddingLeft - paddingRight; - int availableHeight = getHeight() - paddingTop - paddingBottom; - - // Recreate the setup text. - mSetupTextLayout = new StaticLayout( - getResources().getText(R.string.gadget_setup_text), mPaint, availableWidth, - Layout.Alignment.ALIGN_CENTER, 1, 0, true); - if (mSetupTextLayout.getLineCount() == 1) { - // The text fits in a single line. No need to draw the setup icon. - int size = Math.min(iconSize, Math.min(availableWidth, - availableHeight - mSetupTextLayout.getHeight())); - mRect.set(0, 0, size, size); - mRect.offsetTo((getWidth() - mRect.width()) / 2, - (getHeight() - mRect.height() - mSetupTextLayout.getHeight() - - grid.iconDrawablePaddingPx) / 2); - - mTopCornerDrawable.setBounds(mRect); - - // Update left and top to indicate the position where the text will be drawn. - mRect.left = paddingLeft; - mRect.top = mRect.bottom + grid.iconDrawablePaddingPx; - } else { - // The text can't be drawn in a single line. Draw a setup icon instead. - mSetupTextLayout = null; - int size = Math.min(iconSize, Math.min( - getWidth() - paddingLeft - paddingRight, - getHeight() - paddingTop - paddingBottom)); - mRect.set(0, 0, size, size); - mRect.offsetTo((getWidth() - mRect.width()) / 2, (getHeight() - mRect.height()) / 2); - mCenterDrawable.setBounds(mRect); - - size = Math.min(size / 2, - Math.max(mRect.top - paddingTop, mRect.left - paddingLeft)); - mTopCornerDrawable.setBounds(paddingLeft, paddingTop, - paddingLeft + size, paddingTop + size); - } - mDrawableSizeChanged = false; - } + if (mDrawableSizeChanged) { + updateDrawableBounds(); + mDrawableSizeChanged = false; + } - if (mSetupTextLayout == null) { - mCenterDrawable.draw(canvas); - mTopCornerDrawable.draw(canvas); - } else { - canvas.save(); - canvas.translate(mRect.left, mRect.top); - mSetupTextLayout.draw(canvas); - canvas.restore(); - mTopCornerDrawable.draw(canvas); - } + mCenterDrawable.draw(canvas); + if (mSettingIconDrawable != null) { + mSettingIconDrawable.draw(canvas); } + if (mSetupTextLayout != null) { + canvas.save(); + canvas.translate(mRect.left, mRect.top); + mSetupTextLayout.draw(canvas); + canvas.restore(); + } + } } -- cgit v1.2.3 From 522142af51fed5d23492c00bc8a37ec0cca8fdcc Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 17 Aug 2015 13:04:40 -0700 Subject: Removing call to isButtonPressed as its only Lollipop and above Change-Id: I0d70befa25baf4864303833111652dbf1d19daa5 --- src/com/android/launcher3/StylusEventHelper.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/com/android/launcher3/StylusEventHelper.java b/src/com/android/launcher3/StylusEventHelper.java index da46e6a54..e03273a6e 100644 --- a/src/com/android/launcher3/StylusEventHelper.java +++ b/src/com/android/launcher3/StylusEventHelper.java @@ -1,8 +1,5 @@ package com.android.launcher3; -import com.android.launcher3.Utilities; - -import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; @@ -77,8 +74,9 @@ public class StylusEventHelper { * @param event The event to check. * @return Whether a stylus button press occurred. */ - public static boolean isStylusButtonPressed(MotionEvent event) { + private static boolean isStylusButtonPressed(MotionEvent event) { return event.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS - && event.isButtonPressed(MotionEvent.BUTTON_SECONDARY); + && ((event.getButtonState() & MotionEvent.BUTTON_SECONDARY) + == MotionEvent.BUTTON_SECONDARY); } } \ No newline at end of file -- cgit v1.2.3 From 9fc953b94dbc6b99e6de08c9dcc80a0cb8e3e319 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Mon, 17 Aug 2015 12:24:25 -0700 Subject: Version code cleanup > Renaming Lmp to Lollipop > Lollipop_MR1 instead of directly using 22 > Using M APIs directly instead of reflection Change-Id: I10a307f46e3be15b3299f549a2fd7e0e215a6a1b --- .../android/launcher3/WallpaperCropActivity.java | 6 +-- .../android/launcher3/WallpaperPickerActivity.java | 6 +-- src/com/android/launcher3/BubbleTextView.java | 2 +- src/com/android/launcher3/ButtonDropTarget.java | 9 ++-- src/com/android/launcher3/DragView.java | 6 +-- src/com/android/launcher3/Folder.java | 4 +- src/com/android/launcher3/Launcher.java | 54 ++++++---------------- src/com/android/launcher3/LauncherAppState.java | 2 +- .../launcher3/LauncherBackupAgentHelper.java | 2 +- src/com/android/launcher3/LauncherClings.java | 5 +- src/com/android/launcher3/LauncherProvider.java | 2 +- .../LauncherStateTransitionAnimation.java | 10 ++-- src/com/android/launcher3/PagedView.java | 2 +- .../launcher3/PendingAppWidgetHostView.java | 2 +- src/com/android/launcher3/UninstallDropTarget.java | 2 +- src/com/android/launcher3/Utilities.java | 41 ++++++++-------- src/com/android/launcher3/Workspace.java | 2 +- .../launcher3/compat/AppWidgetManagerCompat.java | 2 +- .../compat/AppWidgetManagerCompatV16.java | 6 +-- .../launcher3/compat/LauncherAppsCompat.java | 2 +- .../launcher3/compat/LauncherAppsCompatV16.java | 3 +- .../launcher3/compat/PackageInstallerCompat.java | 2 +- .../android/launcher3/compat/UserHandleCompat.java | 10 ++-- .../launcher3/compat/UserManagerCompat.java | 4 +- .../launcher3/util/ManagedProfileHeuristic.java | 4 +- .../launcher3/util/UiThreadCircularReveal.java | 2 +- src/com/android/launcher3/util/WallpaperUtils.java | 4 +- .../launcher3/widget/WidgetHostViewLoader.java | 3 +- .../launcher3/widget/WidgetsListAdapter.java | 2 +- 29 files changed, 87 insertions(+), 114 deletions(-) diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java index f2bb50944..f2459dd3e 100644 --- a/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java +++ b/WallpaperPicker/src/com/android/launcher3/WallpaperCropActivity.java @@ -223,14 +223,12 @@ public class WallpaperCropActivity extends BaseActivity implements Handler.Callb @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) protected boolean isActivityDestroyed() { - return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) - && isDestroyed(); + return Utilities.ATLEAST_JB_MR1 && isDestroyed(); } @Thunk void addReusableBitmap(TileSource src) { synchronized (mReusableBitmaps) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT - && src instanceof BitmapRegionTileSource) { + if (Utilities.ATLEAST_KITKAT && src instanceof BitmapRegionTileSource) { Bitmap preview = ((BitmapRegionTileSource) src).getBitmap(); if (preview != null && preview.isMutable()) { mReusableBitmaps.add(preview); diff --git a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java index 75d874552..59858501a 100644 --- a/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java +++ b/WallpaperPicker/src/com/android/launcher3/WallpaperPickerActivity.java @@ -977,10 +977,8 @@ public class WallpaperPickerActivity extends WallpaperCropActivity { if (partner == null || !partner.hideDefaultWallpaper()) { // Add an entry for the default wallpaper (stored in system resources) - WallpaperTileInfo defaultWallpaperInfo = - (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) - ? getPreKKDefaultWallpaperInfo() - : getDefaultWallpaper(); + WallpaperTileInfo defaultWallpaperInfo = Utilities.ATLEAST_KITKAT + ? getDefaultWallpaper() : getPreKKDefaultWallpaperInfo(); if (defaultWallpaperInfo != null) { bundled.add(0, defaultWallpaperInfo); } diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 1bcaab519..507087824 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -510,7 +510,7 @@ public class BubbleTextView extends TextView mIcon.setBounds(0, 0, iconSize, iconSize); } if (mLayoutHorizontal) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + if (Utilities.ATLEAST_JB_MR1) { setCompoundDrawablesRelative(mIcon, null, null, null); } else { setCompoundDrawables(mIcon, null, null, null); diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java index b7f89d02a..2baa6d8ee 100644 --- a/src/com/android/launcher3/ButtonDropTarget.java +++ b/src/com/android/launcher3/ButtonDropTarget.java @@ -24,7 +24,6 @@ import android.animation.ValueAnimator.AnimatorUpdateListener; import android.annotation.TargetApi; import android.content.Context; import android.content.res.ColorStateList; -import android.content.res.Configuration; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.PointF; @@ -93,7 +92,7 @@ public abstract class ButtonDropTarget extends TextView // drawableLeft and drawableStart. mDrawable = getResources().getDrawable(resId); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + if (Utilities.ATLEAST_JB_MR1) { setCompoundDrawablesRelativeWithIntrinsicBounds(mDrawable, null, null, null); } else { setCompoundDrawablesWithIntrinsicBounds(mDrawable, null, null, null); @@ -114,7 +113,7 @@ public abstract class ButtonDropTarget extends TextView @Override public final void onDragEnter(DragObject d) { d.dragView.setColor(mHoverColor); - if (Utilities.isLmpOrAbove()) { + if (Utilities.ATLEAST_LOLLIPOP) { animateTextColor(mHoverColor); } else { if (mCurrentFilter == null) { @@ -131,8 +130,8 @@ public abstract class ButtonDropTarget extends TextView // Do nothing } - protected void resetHoverColor() { - if (Utilities.isLmpOrAbove()) { + protected void resetHoverColor() { + if (Utilities.ATLEAST_LOLLIPOP) { animateTextColor(mOriginalTextColor.getDefaultColor()); } else { mDrawable.setColorFilter(null); diff --git a/src/com/android/launcher3/DragView.java b/src/com/android/launcher3/DragView.java index dfa8202a7..2acfc6140 100644 --- a/src/com/android/launcher3/DragView.java +++ b/src/com/android/launcher3/DragView.java @@ -131,7 +131,7 @@ public class DragView extends View { measure(ms, ms); mPaint = new Paint(Paint.FILTER_BITMAP_FLAG); - if (Utilities.isLmpOrAbove()) { + if (Utilities.ATLEAST_LOLLIPOP) { setElevation(getResources().getDimension(R.dimen.drag_elevation)); } } @@ -252,14 +252,14 @@ public class DragView extends View { setColorScale(color, m2); m1.postConcat(m2); - if (Utilities.isLmpOrAbove()) { + if (Utilities.ATLEAST_LOLLIPOP) { animateFilterTo(m1.getArray()); } else { mPaint.setColorFilter(new ColorMatrixColorFilter(m1)); invalidate(); } } else { - if (!Utilities.isLmpOrAbove() || mCurrentFilter == null) { + if (!Utilities.ATLEAST_LOLLIPOP || mCurrentFilter == null) { mPaint.setColorFilter(null); invalidate(); } else { diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java index 7b88a8865..c1aa35669 100644 --- a/src/com/android/launcher3/Folder.java +++ b/src/com/android/launcher3/Folder.java @@ -453,7 +453,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList Animator openFolderAnim = null; final Runnable onCompleteRunnable; - if (!Utilities.isLmpOrAbove()) { + if (!Utilities.ATLEAST_LOLLIPOP) { positionAndSizeAsIcon(); centerAboutIcon(); @@ -568,7 +568,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList public void onAnimationEnd(Animator animation) { mFolderName.animate().setDuration(FOLDER_NAME_ANIMATION_DURATION) .translationX(0) - .setInterpolator(Utilities.isLmpOrAbove() ? + .setInterpolator(Utilities.ATLEAST_LOLLIPOP ? AnimationUtils.loadInterpolator(mLauncher, android.R.interpolator.fast_out_slow_in) : new LogDecelerateInterpolator(100, 0)); diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 19ddeec4a..5aeacaa57 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -116,8 +116,6 @@ import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.text.DateFormat; import java.util.ArrayList; import java.util.Collection; @@ -360,18 +358,6 @@ public class Launcher extends Activity } } - // TODO: remove this field and call method directly when Launcher3 can depend on M APIs - private static Method sClipRevealMethod = null; - static { - Class activityOptionsClass = ActivityOptions.class; - try { - sClipRevealMethod = activityOptionsClass.getDeclaredMethod("makeClipRevealAnimation", - View.class, int.class, int.class, int.class, int.class); - } catch (Exception e) { - // Earlier version - } - } - @Thunk Runnable mBuildLayersRunnable = new Runnable() { public void run() { if (mWorkspace != null) { @@ -667,7 +653,7 @@ public class Launcher extends Activity @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public static int generateViewId() { - if (Build.VERSION.SDK_INT >= 17) { + if (Utilities.ATLEAST_JB_MR1) { return View.generateViewId(); } else { // View.generateViewId() is not available. The following fallback logic is a copy @@ -1653,18 +1639,18 @@ public class Launcher extends Activity } registerReceiver(mReceiver, filter); FirstFrameAnimatorHelper.initializeDrawListener(getWindow().getDecorView()); - setupTransparentSystemBarsForLmp(); + setupTransparentSystemBarsForLollipop(); mAttached = true; mVisible = true; } /** - * Sets up transparent navigation and status bars in LMP. + * Sets up transparent navigation and status bars in Lollipop. * This method is a no-op for other platform versions. */ @TargetApi(Build.VERSION_CODES.LOLLIPOP) - private void setupTransparentSystemBarsForLmp() { - if (Utilities.isLmpOrAbove()) { + private void setupTransparentSystemBarsForLollipop() { + if (Utilities.ATLEAST_LOLLIPOP) { Window window = getWindow(); window.getAttributes().systemUiVisibility |= (View.SYSTEM_UI_FLAG_LAYOUT_STABLE @@ -2883,8 +2869,7 @@ public class Launcher extends Activity Bundle optsBundle = null; if (useLaunchAnimation) { ActivityOptions opts = null; - if (sClipRevealMethod != null) { - // TODO: call method directly when Launcher3 can depend on M APIs + if (Utilities.ATLEAST_MARSHMALLOW) { int left = 0, top = 0; int width = v.getMeasuredWidth(), height = v.getMeasuredHeight(); if (v instanceof TextView) { @@ -2898,22 +2883,12 @@ public class Launcher extends Activity height = bounds.height(); } } - try { - opts = (ActivityOptions) sClipRevealMethod.invoke(null, v, - left, top, width, height); - } catch (IllegalAccessException e) { - Log.d(TAG, "Could not call makeClipRevealAnimation: " + e); - sClipRevealMethod = null; - } catch (InvocationTargetException e) { - Log.d(TAG, "Could not call makeClipRevealAnimation: " + e); - sClipRevealMethod = null; - } - } - if (opts == null && !Utilities.isLmpOrAbove()) { + opts = ActivityOptions.makeClipRevealAnimation(v, left, top, width, height); + } else if (!Utilities.ATLEAST_LOLLIPOP) { // Below L, we use a scale up animation opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.getMeasuredWidth(), v.getMeasuredHeight()); - } else if (opts == null && Utilities.isLmpMR1()) { + } else if (Utilities.ATLEAST_LOLLIPOP_MR1) { // On L devices, we use the device default slide-up transition. // On L MR1 devices, we a custom version of the slide-up transition which // doesn't have the delay present in the device default. @@ -3028,7 +3003,7 @@ public class Launcher extends Activity ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(mFolderIconImageView, alpha, scaleX, scaleY); - if (Utilities.isLmpOrAbove()) { + if (Utilities.ATLEAST_LOLLIPOP) { oa.setInterpolator(new LogDecelerateInterpolator(100, 0)); } oa.setDuration(getResources().getInteger(R.integer.config_folderExpandDuration)); @@ -4324,13 +4299,14 @@ public class Launcher extends Activity return oriMap[(d.getRotation() + indexOffset) % 4]; } + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) public void lockScreenOrientation() { if (mRotationEnabled) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { + if (Utilities.ATLEAST_JB_MR2) { + setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED); + } else { setRequestedOrientation(mapConfigurationOriActivityInfoOri(getResources() .getConfiguration().orientation)); - } else { - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED); } } } @@ -4534,7 +4510,7 @@ public class Launcher extends Activity public ItemInfo createAppDragInfo(Intent appLaunchIntent) { // Called from search suggestion UserHandleCompat user = null; - if (Utilities.isLmpOrAbove()) { + if (Utilities.ATLEAST_LOLLIPOP) { UserHandle userHandle = appLaunchIntent.getParcelableExtra(Intent.EXTRA_USER); if (userHandle != null) { user = UserHandleCompat.fromUser(userHandle); diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 52f85ea42..d87ad67e5 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -127,7 +127,7 @@ public class LauncherAppState { LauncherModel setLauncher(Launcher launcher) { getLauncherProvider().setLauncherProviderChangeListener(launcher); mModel.initialize(launcher); - mAccessibilityDelegate = ((launcher != null) && Utilities.isLmpOrAbove()) ? + mAccessibilityDelegate = ((launcher != null) && Utilities.ATLEAST_LOLLIPOP) ? new LauncherAccessibilityDelegate(launcher) : null; return mModel; } diff --git a/src/com/android/launcher3/LauncherBackupAgentHelper.java b/src/com/android/launcher3/LauncherBackupAgentHelper.java index 3debef60e..8eb4e6369 100644 --- a/src/com/android/launcher3/LauncherBackupAgentHelper.java +++ b/src/com/android/launcher3/LauncherBackupAgentHelper.java @@ -65,7 +65,7 @@ public class LauncherBackupAgentHelper extends BackupAgentHelper { @Override public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException { - if (!Utilities.isLmpOrAbove()) { + if (!Utilities.ATLEAST_LOLLIPOP) { // No restore for old devices. Log.i(TAG, "You shall not pass!!!"); Log.d(TAG, "Restore is only supported on devices running Lollipop and above."); diff --git a/src/com/android/launcher3/LauncherClings.java b/src/com/android/launcher3/LauncherClings.java index c44ea6bcd..747028474 100644 --- a/src/com/android/launcher3/LauncherClings.java +++ b/src/com/android/launcher3/LauncherClings.java @@ -16,8 +16,6 @@ package com.android.launcher3; -import android.accounts.Account; -import android.accounts.AccountManager; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.annotation.TargetApi; @@ -36,6 +34,7 @@ import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.accessibility.AccessibilityManager; + import com.android.launcher3.util.Thunk; class LauncherClings implements OnClickListener { @@ -225,7 +224,7 @@ class LauncherClings implements OnClickListener { // Restricted secondary users (child mode) will potentially have very few apps // seeded when they start up for the first time. Clings won't work well with that - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + if (Utilities.ATLEAST_JB_MR2) { UserManager um = (UserManager) mLauncher.getSystemService(Context.USER_SERVICE); Bundle restrictions = um.getUserRestrictions(); if (restrictions.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, false)) { diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index 059971405..20844ec13 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -402,7 +402,7 @@ public class LauncherProvider extends ContentProvider { @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) private AutoInstallsLayout createWorkspaceLoaderFromAppRestriction() { // UserManager.getApplicationRestrictions() requires minSdkVersion >= 18 - if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { + if (!Utilities.ATLEAST_JB_MR2) { return null; } diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java index 5a3f3dc7a..cdde8c13f 100644 --- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java +++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java @@ -205,7 +205,7 @@ public class LauncherStateTransitionAnimation { final boolean animated, final PrivateTransitionCallbacks pCb) { final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet(); final Resources res = mLauncher.getResources(); - final boolean material = Utilities.isLmpOrAbove(); + final boolean material = Utilities.ATLEAST_LOLLIPOP; final int revealDuration = res.getInteger(R.integer.config_overlayRevealTime); final int itemsAlphaStagger = res.getInteger(R.integer.config_overlayItemsAlphaStagger); @@ -358,12 +358,11 @@ public class LauncherStateTransitionAnimation { dispatchOnLauncherTransitionStart(toView, animated, false); // Enable all necessary layers - boolean isLmpOrAbove = Utilities.isLmpOrAbove(); for (View v : layerViews.keySet()) { if (layerViews.get(v) == BUILD_AND_SET_LAYER) { v.setLayerType(View.LAYER_TYPE_HARDWARE, null); } - if (isLmpOrAbove && Utilities.isViewAttachedToWindow(v)) { + if (Utilities.ATLEAST_LOLLIPOP && Utilities.isViewAttachedToWindow(v)) { v.buildLayer(); } } @@ -486,7 +485,7 @@ public class LauncherStateTransitionAnimation { final PrivateTransitionCallbacks pCb) { final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet(); final Resources res = mLauncher.getResources(); - final boolean material = Utilities.isLmpOrAbove(); + final boolean material = Utilities.ATLEAST_LOLLIPOP; final int revealDuration = res.getInteger(R.integer.config_overlayRevealTime); final int itemsAlphaStagger = res.getInteger(R.integer.config_overlayItemsAlphaStagger); @@ -668,12 +667,11 @@ public class LauncherStateTransitionAnimation { dispatchOnLauncherTransitionStart(toView, animated, false); // Enable all necessary layers - boolean isLmpOrAbove = Utilities.isLmpOrAbove(); for (View v : layerViews.keySet()) { if (layerViews.get(v) == BUILD_AND_SET_LAYER) { v.setLayerType(View.LAYER_TYPE_HARDWARE, null); } - if (isLmpOrAbove && Utilities.isViewAttachedToWindow(v)) { + if (Utilities.ATLEAST_LOLLIPOP && Utilities.isViewAttachedToWindow(v)) { v.buildLayer(); } } diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 218c1a36f..05f0a0553 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -2293,7 +2293,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc // Besides disabling the accessibility long-click, this also prevents this view from getting // accessibility focus. info.setLongClickable(false); - if (Utilities.isLmpOrAbove()) { + if (Utilities.ATLEAST_LOLLIPOP) { info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK); } } diff --git a/src/com/android/launcher3/PendingAppWidgetHostView.java b/src/com/android/launcher3/PendingAppWidgetHostView.java index e8c8b8ec9..40eadabd5 100644 --- a/src/com/android/launcher3/PendingAppWidgetHostView.java +++ b/src/com/android/launcher3/PendingAppWidgetHostView.java @@ -78,7 +78,7 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView implemen setBackgroundResource(R.drawable.quantum_panel_dark); setWillNotDraw(false); - if (Utilities.isLmpOrAbove()) { + if (Utilities.ATLEAST_LOLLIPOP) { setElevation(getResources().getDimension(R.dimen.pending_widget_elevation)); } } diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java index 0819f8ce0..955d4013c 100644 --- a/src/com/android/launcher3/UninstallDropTarget.java +++ b/src/com/android/launcher3/UninstallDropTarget.java @@ -38,7 +38,7 @@ public class UninstallDropTarget extends ButtonDropTarget { @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) public static boolean supportsDrop(Context context, Object info) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + if (Utilities.ATLEAST_JB_MR2) { UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE); Bundle restrictions = userManager.getUserRestrictions(); if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false) diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 8fd298df7..adedd33b2 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -87,6 +87,24 @@ public final class Utilities { private static final int[] sLoc0 = new int[2]; private static final int[] sLoc1 = new int[2]; + // TODO: use Build.VERSION_CODES when available + public static final boolean ATLEAST_MARSHMALLOW = Build.VERSION.SDK_INT >= 23; + + public static final boolean ATLEAST_LOLLIPOP_MR1 = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1; + + public static final boolean ATLEAST_LOLLIPOP = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; + + public static final boolean ATLEAST_KITKAT = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; + + public static final boolean ATLEAST_JB_MR1 = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1; + + public static final boolean ATLEAST_JB_MR2 = + Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2; + // To turn on these properties, type // adb shell setprop log.tag.PROPERTY_NAME [VERBOSE | SUPPRESS] private static final String FORCE_ENABLE_ROTATION_PROPERTY = "launcher_force_rotate"; @@ -110,23 +128,6 @@ public final class Utilities { return sForceEnableRotation || context.getResources().getBoolean(R.bool.allow_rotation); } - /** - * Indicates if the device is running LMP or higher. - */ - public static boolean isLmpOrAbove() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; - } - - public static boolean isLmpMR1OrAbove() { - // TODO(adamcohen): update to Build.VERSION_CODES.LOLLIPOP_MR1 once building against 22; - return Build.VERSION.SDK_INT >= 22; - } - - public static boolean isLmpMR1() { - // TODO(adamcohen): update to Build.VERSION_CODES.LOLLIPOP_MR1 once building against 22; - return Build.VERSION.SDK_INT == 22; - } - public static Bitmap createIconBitmap(Cursor c, int iconIndex, Context context) { byte[] data = c.getBlob(iconIndex); try { @@ -517,7 +518,7 @@ public final class Utilities { @TargetApi(Build.VERSION_CODES.KITKAT) public static boolean isViewAttachedToWindow(View v) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + if (ATLEAST_KITKAT) { return v.isAttachedToWindow(); } else { // A proxy call which returns null, if the view is not attached to the window. @@ -544,7 +545,7 @@ public final class Utilities { AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); for (AppWidgetProviderInfo info : appWidgetManager.getInstalledProviders()) { if (info.provider.getPackageName().equals(providerPkg)) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + if (ATLEAST_JB_MR1) { if ((info.widgetCategory & AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX) != 0) { return info; } else if (defaultWidgetForSearchPackage == null) { @@ -655,7 +656,7 @@ public final class Utilities { @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public static boolean isRtl(Resources res) { - return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) && + return ATLEAST_JB_MR1 && (res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL); } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 08e642948..61d09a95c 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -2013,7 +2013,7 @@ public class Workspace extends PagedView } public void updateAccessibilityFlags() { - if (Utilities.isLmpOrAbove()) { + if (Utilities.ATLEAST_LOLLIPOP) { int total = getPageCount(); for (int i = numCustomPages(); i < total; i++) { updateAccessibilityFlags((CellLayout) getPageAt(i), i); diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java index 7aa36d447..434f13dcc 100644 --- a/src/com/android/launcher3/compat/AppWidgetManagerCompat.java +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompat.java @@ -40,7 +40,7 @@ public abstract class AppWidgetManagerCompat { public static AppWidgetManagerCompat getInstance(Context context) { synchronized (sInstanceLock) { if (sInstance == null) { - if (Utilities.isLmpOrAbove()) { + if (Utilities.ATLEAST_LOLLIPOP) { sInstance = new AppWidgetManagerCompatVL(context.getApplicationContext()); } else { sInstance = new AppWidgetManagerCompatV16(context.getApplicationContext()); diff --git a/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java b/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java index f7f4b7e4f..463cf902d 100644 --- a/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java +++ b/src/com/android/launcher3/compat/AppWidgetManagerCompatV16.java @@ -54,10 +54,10 @@ class AppWidgetManagerCompatV16 extends AppWidgetManagerCompat { @Override public boolean bindAppWidgetIdIfAllowed(int appWidgetId, AppWidgetProviderInfo info, Bundle options) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { - return mAppWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, info.provider); - } else { + if (Utilities.ATLEAST_JB_MR1) { return mAppWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, info.provider, options); + } else { + return mAppWidgetManager.bindAppWidgetIdIfAllowed(appWidgetId, info.provider); } } diff --git a/src/com/android/launcher3/compat/LauncherAppsCompat.java b/src/com/android/launcher3/compat/LauncherAppsCompat.java index 5858bc8b9..95e3ba902 100644 --- a/src/com/android/launcher3/compat/LauncherAppsCompat.java +++ b/src/com/android/launcher3/compat/LauncherAppsCompat.java @@ -53,7 +53,7 @@ public abstract class LauncherAppsCompat { public static LauncherAppsCompat getInstance(Context context) { synchronized (sInstanceLock) { if (sInstance == null) { - if (Utilities.isLmpOrAbove()) { + if (Utilities.ATLEAST_LOLLIPOP) { sInstance = new LauncherAppsCompatVL(context.getApplicationContext()); } else { sInstance = new LauncherAppsCompatV16(context.getApplicationContext()); diff --git a/src/com/android/launcher3/compat/LauncherAppsCompatV16.java b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java index ac3d252f5..339c457e1 100644 --- a/src/com/android/launcher3/compat/LauncherAppsCompatV16.java +++ b/src/com/android/launcher3/compat/LauncherAppsCompatV16.java @@ -31,6 +31,7 @@ import android.os.Build; import android.os.Bundle; import android.provider.Settings; +import com.android.launcher3.Utilities; import com.android.launcher3.util.Thunk; import java.util.ArrayList; @@ -188,7 +189,7 @@ public class LauncherAppsCompatV16 extends LauncherAppsCompat { // when moving a package or mounting/un-mounting external storage. Assume that // it is a replacing operation. final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, - Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT); + !Utilities.ATLEAST_KITKAT); String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); for (OnAppsChangedCallbackCompat callback : getCallbacks()) { callback.onPackagesAvailable(packages, user, replacing); diff --git a/src/com/android/launcher3/compat/PackageInstallerCompat.java b/src/com/android/launcher3/compat/PackageInstallerCompat.java index c49908328..ec5014d7c 100644 --- a/src/com/android/launcher3/compat/PackageInstallerCompat.java +++ b/src/com/android/launcher3/compat/PackageInstallerCompat.java @@ -34,7 +34,7 @@ public abstract class PackageInstallerCompat { public static PackageInstallerCompat getInstance(Context context) { synchronized (sInstanceLock) { if (sInstance == null) { - if (Utilities.isLmpOrAbove()) { + if (Utilities.ATLEAST_LOLLIPOP) { sInstance = new PackageInstallerCompatVL(context); } else { sInstance = new PackageInstallerCompatV16(); diff --git a/src/com/android/launcher3/compat/UserHandleCompat.java b/src/com/android/launcher3/compat/UserHandleCompat.java index ab4b7216b..567022b43 100644 --- a/src/com/android/launcher3/compat/UserHandleCompat.java +++ b/src/com/android/launcher3/compat/UserHandleCompat.java @@ -34,7 +34,7 @@ public class UserHandleCompat { @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public static UserHandleCompat myUserHandle() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + if (Utilities.ATLEAST_JB_MR1) { return new UserHandleCompat(android.os.Process.myUserHandle()); } else { return new UserHandleCompat(); @@ -55,7 +55,7 @@ public class UserHandleCompat { @Override public String toString() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + if (Utilities.ATLEAST_JB_MR1) { return mUser.toString(); } else { return ""; @@ -67,7 +67,7 @@ public class UserHandleCompat { if (!(other instanceof UserHandleCompat)) { return false; } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + if (Utilities.ATLEAST_JB_MR1) { return mUser.equals(((UserHandleCompat) other).mUser); } else { return true; @@ -76,7 +76,7 @@ public class UserHandleCompat { @Override public int hashCode() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + if (Utilities.ATLEAST_JB_MR1) { return mUser.hashCode(); } else { return 0; @@ -89,7 +89,7 @@ public class UserHandleCompat { * profiles so this is a no-op. */ public void addToIntent(Intent intent, String name) { - if (Utilities.isLmpOrAbove() && mUser != null) { + if (Utilities.ATLEAST_LOLLIPOP && mUser != null) { intent.putExtra(name, mUser); } } diff --git a/src/com/android/launcher3/compat/UserManagerCompat.java b/src/com/android/launcher3/compat/UserManagerCompat.java index 2ff1e7b74..f708004a3 100644 --- a/src/com/android/launcher3/compat/UserManagerCompat.java +++ b/src/com/android/launcher3/compat/UserManagerCompat.java @@ -34,9 +34,9 @@ public abstract class UserManagerCompat { public static UserManagerCompat getInstance(Context context) { synchronized (sInstanceLock) { if (sInstance == null) { - if (Utilities.isLmpOrAbove()) { + if (Utilities.ATLEAST_LOLLIPOP) { sInstance = new UserManagerCompatVL(context.getApplicationContext()); - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + } else if (Utilities.ATLEAST_JB_MR1) { sInstance = new UserManagerCompatV17(context.getApplicationContext()); } else { sInstance = new UserManagerCompatV16(); diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java index b37f44719..74fc92a04 100644 --- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java +++ b/src/com/android/launcher3/util/ManagedProfileHeuristic.java @@ -68,7 +68,7 @@ public class ManagedProfileHeuristic { private static final long AUTO_ADD_TO_FOLDER_DURATION = 8 * 60 * 60 * 1000; public static ManagedProfileHeuristic get(Context context, UserHandleCompat user) { - if (Utilities.isLmpOrAbove() && !UserHandleCompat.myUserHandle().equals(user)) { + if (Utilities.ATLEAST_LOLLIPOP && !UserHandleCompat.myUserHandle().equals(user)) { return new ManagedProfileHeuristic(context, user); } return null; @@ -296,7 +296,7 @@ public class ManagedProfileHeuristic { * Verifies that entries corresponding to {@param users} exist and removes all invalid entries. */ public static void processAllUsers(List users, Context context) { - if (!Utilities.isLmpOrAbove()) { + if (!Utilities.ATLEAST_LOLLIPOP) { return; } UserManagerCompat userManager = UserManagerCompat.getInstance(context); diff --git a/src/com/android/launcher3/util/UiThreadCircularReveal.java b/src/com/android/launcher3/util/UiThreadCircularReveal.java index 3ca3aeeee..f2b5e5e15 100644 --- a/src/com/android/launcher3/util/UiThreadCircularReveal.java +++ b/src/com/android/launcher3/util/UiThreadCircularReveal.java @@ -47,7 +47,7 @@ public class UiThreadCircularReveal { float progress = arg0.getAnimatedFraction(); outlineProvider.setProgress(progress); revealView.invalidateOutline(); - if (!Utilities.isLmpMR1OrAbove()) { + if (!Utilities.ATLEAST_LOLLIPOP_MR1) { revealView.invalidate(); } } diff --git a/src/com/android/launcher3/util/WallpaperUtils.java b/src/com/android/launcher3/util/WallpaperUtils.java index 53b2acd84..b9fccbcfd 100644 --- a/src/com/android/launcher3/util/WallpaperUtils.java +++ b/src/com/android/launcher3/util/WallpaperUtils.java @@ -24,6 +24,8 @@ import android.graphics.Point; import android.os.Build; import android.view.WindowManager; +import com.android.launcher3.Utilities; + /** * Utility methods for wallpaper management. */ @@ -99,7 +101,7 @@ public final class WallpaperUtils { int maxDim = Math.max(maxDims.x, maxDims.y); int minDim = Math.max(minDims.x, minDims.y); - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) { + if (Utilities.ATLEAST_JB_MR1) { Point realSize = new Point(); windowManager.getDefaultDisplay().getRealSize(realSize); maxDim = Math.max(realSize.x, realSize.y); diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java index 30b3d581a..461aebb6b 100644 --- a/src/com/android/launcher3/widget/WidgetHostViewLoader.java +++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java @@ -15,6 +15,7 @@ import com.android.launcher3.DragLayer; import com.android.launcher3.DragSource; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppWidgetProviderInfo; +import com.android.launcher3.Utilities; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.util.Thunk; @@ -131,7 +132,7 @@ public class WidgetHostViewLoader implements DragListener { public static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) { Bundle options = null; Rect rect = new Rect(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + if (Utilities.ATLEAST_JB_MR1) { AppWidgetResizeFrame.getWidgetSizeRanges(launcher, info.spanX, info.spanY, rect); Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(launcher, info.componentName, null); diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java index a54626a39..f1cde299d 100644 --- a/src/com/android/launcher3/widget/WidgetsListAdapter.java +++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java @@ -169,7 +169,7 @@ public class WidgetsListAdapter extends Adapter { // if the end padding is 0, then container view (horizontal scroll view) doesn't respect // the end of the linear layout width + the start padding and doesn't allow scrolling. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + if (Utilities.ATLEAST_JB_MR1) { cellList.setPaddingRelative(mIndent, 0, 1, 0); } else { cellList.setPadding(mIndent, 0, 1, 0); -- cgit v1.2.3 From 7c3cccf427be23990d7bbc797a3106de69389586 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 18 Aug 2015 18:48:38 -0700 Subject: Fixing empty screen created at the end, even when dragging the last item on the last screen. Change-Id: If0d4faf0ca15e71facb6ed2fd81ed6a589527836 --- src/com/android/launcher3/Workspace.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 61d09a95c..44d70ba79 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -2319,14 +2319,14 @@ public class Workspace extends PagedView throw new IllegalStateException(msg); } - DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(), - DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale, accessible); - dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor()); - if (child.getParent() instanceof ShortcutAndWidgetContainer) { mDragSourceInternal = (ShortcutAndWidgetContainer) child.getParent(); } + DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(), + DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale, accessible); + dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor()); + b.recycle(); } -- cgit v1.2.3 From 15f8b17adb36e7345e39cc1c431f8c1abd84f832 Mon Sep 17 00:00:00 2001 From: Winson Date: Wed, 19 Aug 2015 11:02:39 -0700 Subject: Deferring the move to the default screen until after we callback to the callbacks. - Since move to default screen starts the scroller immediately, any delays in handling onNewIntent and onHomeIntent in the callbacks will cause the scroller to skip frames the next time it updates. This change will defer updating the page to the default screen until after onNewIntent is called back (and all its posted runnables). Bug: 22929080 Change-Id: Ibab6106938721702d4da23faaca99039861e10dc --- src/com/android/launcher3/Launcher.java | 44 ++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 298b2c469..203e2247c 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1867,29 +1867,22 @@ public class Launcher extends Activity super.onNewIntent(intent); // Close the menu - if (Intent.ACTION_MAIN.equals(intent.getAction())) { + Folder openFolder = mWorkspace.getOpenFolder(); + boolean alreadyOnHome = mHasFocus && ((intent.getFlags() & + Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) + != Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); + boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction()); + if (isActionMain) { // also will cancel mWaitingForResult. closeSystemDialogs(); - final boolean alreadyOnHome = mHasFocus && ((intent.getFlags() & - Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) - != Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); - if (mWorkspace == null) { // Can be cases where mWorkspace is null, this prevents a NPE return; } - Folder openFolder = mWorkspace.getOpenFolder(); // In all these cases, only animate if we're already on home mWorkspace.exitWidgetResizeMode(); - boolean moveToDefaultScreen = mLauncherCallbacks != null ? - mLauncherCallbacks.shouldMoveToDefaultScreenOnHomeIntent() : true; - if (alreadyOnHome && mState == State.WORKSPACE && !mWorkspace.isTouchActive() && - openFolder == null && moveToDefaultScreen) { - mWorkspace.moveToDefaultScreen(true); - } - closeFolder(); exitSpringLoadedDragMode(); @@ -1923,13 +1916,30 @@ public class Launcher extends Activity } } - if (DEBUG_RESUME_TIME) { - Log.d(TAG, "Time spent in onNewIntent: " + (System.currentTimeMillis() - startTime)); - } - if (mLauncherCallbacks != null) { mLauncherCallbacks.onNewIntent(intent); } + + // Defer moving to the default screen until after we callback to the LauncherCallbacks + // as slow logic in the callbacks eat into the time the scroller expects for the snapToPage + // animation. + if (isActionMain) { + boolean moveToDefaultScreen = mLauncherCallbacks != null ? + mLauncherCallbacks.shouldMoveToDefaultScreenOnHomeIntent() : true; + if (alreadyOnHome && mState == State.WORKSPACE && !mWorkspace.isTouchActive() && + openFolder == null && moveToDefaultScreen) { + mWorkspace.post(new Runnable() { + @Override + public void run() { + mWorkspace.moveToDefaultScreen(true); + } + }); + } + } + + if (DEBUG_RESUME_TIME) { + Log.d(TAG, "Time spent in onNewIntent: " + (System.currentTimeMillis() - startTime)); + } } @Override -- cgit v1.2.3 From 639e906a0fc205b48512951feec0cbb47513e246 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 19 Aug 2015 19:17:06 -0700 Subject: Fixing work folder addition logic > Showing animation when folder is added > Not showing animation while cling is visible > Checking is loader completed from UI thread > Running bind complete runnables when bind is completed Bug: 21772992 Bug: 23181585 Change-Id: I50742850da8294a877478ce02b107a026f68b563 --- src/com/android/launcher3/Launcher.java | 37 +++++++------ src/com/android/launcher3/LauncherClings.java | 8 +++ src/com/android/launcher3/LauncherModel.java | 78 +++++++++++++-------------- 3 files changed, 64 insertions(+), 59 deletions(-) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 6f2458c11..a59e9ae0c 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -301,6 +301,8 @@ public class Launcher extends Activity private boolean mHasFocus = false; private boolean mAttached = false; + private LauncherClings mClings; + private static LongArrayMap sFolders = new LongArrayMap<>(); private View.OnTouchListener mHapticFeedbackTouchListener; @@ -648,7 +650,7 @@ public class Launcher extends Activity public boolean isDraggingEnabled() { // We prevent dragging when we are loading the workspace as it is possible to pick up a view // that is subsequently removed from the workspace in startBinding(). - return !mModel.isLoadingWorkspace(); + return !isWorkspaceLoading(); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) @@ -3755,11 +3757,12 @@ public class Launcher extends Activity continue; } + final View view; switch (item.itemType) { case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: ShortcutInfo info = (ShortcutInfo) item; - View shortcut = createShortcut(info); + view = createShortcut(info); /* * TODO: FIX collision case @@ -3778,28 +3781,26 @@ public class Launcher extends Activity } } } - - workspace.addInScreenFromBind(shortcut, item.container, item.screenId, item.cellX, - item.cellY, 1, 1); - if (animateIcons) { - // Animate all the applications up now - shortcut.setAlpha(0f); - shortcut.setScaleX(0f); - shortcut.setScaleY(0f); - bounceAnims.add(createNewAppBounceAnimation(shortcut, i)); - newShortcutsScreenId = item.screenId; - } break; case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: - FolderIcon newFolder = FolderIcon.fromXml(R.layout.folder_icon, this, + view = FolderIcon.fromXml(R.layout.folder_icon, this, (ViewGroup) workspace.getChildAt(workspace.getCurrentPage()), (FolderInfo) item, mIconCache); - workspace.addInScreenFromBind(newFolder, item.container, item.screenId, item.cellX, - item.cellY, 1, 1); break; default: throw new RuntimeException("Invalid Item Type"); } + + workspace.addInScreenFromBind(view, item.container, item.screenId, item.cellX, + item.cellY, 1, 1); + if (animateIcons) { + // Animate all the applications up now + view.setAlpha(0f); + view.setScaleX(0f); + view.setScaleY(0f); + bounceAnims.add(createNewAppBounceAnimation(view, i)); + newShortcutsScreenId = item.screenId; + } } if (animateIcons) { @@ -4064,7 +4065,8 @@ public class Launcher extends Activity private boolean canRunNewAppsAnimation() { long diff = System.currentTimeMillis() - mDragController.getLastGestureUpTime(); - return diff > (NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS * 1000); + return diff > (NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS * 1000) + && (mClings == null || !mClings.isVisible()); } private ValueAnimator createNewAppBounceAnimation(View v, int i) { @@ -4491,6 +4493,7 @@ public class Launcher extends Activity // launcher2). Otherwise, we prompt the user upon started for migration LauncherClings launcherClings = new LauncherClings(this); if (launcherClings.shouldShowFirstRunOrMigrationClings()) { + mClings = launcherClings; if (mModel.canMigrateFromOldLauncherDb(this)) { launcherClings.showMigrationCling(); } else { diff --git a/src/com/android/launcher3/LauncherClings.java b/src/com/android/launcher3/LauncherClings.java index 747028474..18fe8ef86 100644 --- a/src/com/android/launcher3/LauncherClings.java +++ b/src/com/android/launcher3/LauncherClings.java @@ -51,6 +51,7 @@ class LauncherClings implements OnClickListener { @Thunk Launcher mLauncher; private LayoutInflater mInflater; + @Thunk boolean mIsVisible; /** Ctor */ public LauncherClings(Launcher launcher) { @@ -91,6 +92,7 @@ class LauncherClings implements OnClickListener { * package was not preinstalled and there exists a db to migrate from. */ public void showMigrationCling() { + mIsVisible = true; mLauncher.hideWorkspaceSearchAndHotseat(); ViewGroup root = (ViewGroup) mLauncher.findViewById(R.id.launcher); @@ -117,6 +119,7 @@ class LauncherClings implements OnClickListener { } public void showLongPressCling(boolean showWelcome) { + mIsVisible = true; ViewGroup root = (ViewGroup) mLauncher.findViewById(R.id.launcher); View cling = mInflater.inflate(R.layout.longpress_cling, root, false); @@ -196,6 +199,7 @@ class LauncherClings implements OnClickListener { mLauncher.getSharedPrefs().edit() .putBoolean(flag, true) .apply(); + mIsVisible = false; if (postAnimationCb != null) { postAnimationCb.run(); } @@ -209,6 +213,10 @@ class LauncherClings implements OnClickListener { } } + public boolean isVisible() { + return mIsVisible; + } + /** Returns whether the clings are enabled or should be shown */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) private boolean areClingsEnabled() { diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 27486822a..e5ca77867 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -34,7 +34,6 @@ import android.content.pm.ResolveInfo; import android.database.Cursor; import android.graphics.Bitmap; import android.net.Uri; -import android.os.Build; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; @@ -259,7 +258,7 @@ public class LauncherModel extends BroadcastReceiver /** Runs the specified runnable immediately if called from the worker thread, otherwise it is * posted on the worker thread handler. */ - private static void runOnWorkerThread(Runnable r) { + @Thunk static void runOnWorkerThread(Runnable r) { if (sWorkerThread.getThreadId() == Process.myTid()) { r.run(); } else { @@ -268,19 +267,6 @@ public class LauncherModel extends BroadcastReceiver } } - /** - * Runs the specified runnable after the loader is complete - */ - @Thunk void runAfterBindCompletes(Runnable r) { - if (isLoadingWorkspace() || !mHasLoaderCompletedOnce) { - synchronized (mBindCompleteRunnables) { - mBindCompleteRunnables.add(r); - } - } else { - runOnWorkerThread(r); - } - } - boolean canMigrateFromOldLauncherDb(Launcher launcher) { return mOldContentProviderExists && !launcher.isLauncherPreinstalled() ; } @@ -894,8 +880,13 @@ public class LauncherModel extends BroadcastReceiver } private void assertWorkspaceLoaded() { - if (LauncherAppState.isDogfoodBuild() && (isLoadingWorkspace() || !mHasLoaderCompletedOnce)) { - throw new RuntimeException("Trying to add shortcut while loader is running"); + if (LauncherAppState.isDogfoodBuild()) { + synchronized (mLock) { + if (!mHasLoaderCompletedOnce || + (mLoaderTask != null && mLoaderTask.mIsLoadingAndBindingWorkspace)) { + throw new RuntimeException("Trying to add shortcut while loader is running"); + } + } } } @@ -1390,16 +1381,6 @@ public class LauncherModel extends BroadcastReceiver mHandler.post(r); } } - - // Run all the bind complete runnables after workspace is bound. - if (!mBindCompleteRunnables.isEmpty()) { - synchronized (mBindCompleteRunnables) { - for (final Runnable r : mBindCompleteRunnables) { - runOnWorkerThread(r); - } - mBindCompleteRunnables.clear(); - } - } } public void stopLoader() { @@ -1441,15 +1422,6 @@ public class LauncherModel extends BroadcastReceiver return mAllAppsLoaded; } - boolean isLoadingWorkspace() { - synchronized (mLock) { - if (mLoaderTask != null) { - return mLoaderTask.isLoadingWorkspace(); - } - } - return false; - } - /** * Runnable for the thread that loads the contents of the launcher: * - workspace icons @@ -1468,10 +1440,6 @@ public class LauncherModel extends BroadcastReceiver mFlags = flags; } - boolean isLoadingWorkspace() { - return mIsLoadingAndBindingWorkspace; - } - private void loadAndBindWorkspace() { mIsLoadingAndBindingWorkspace = true; @@ -2697,13 +2665,24 @@ public class LauncherModel extends BroadcastReceiver callbacks.finishBindingItems(); } + mIsLoadingAndBindingWorkspace = false; + + // Run all the bind complete runnables after workspace is bound. + if (!mBindCompleteRunnables.isEmpty()) { + synchronized (mBindCompleteRunnables) { + for (final Runnable r : mBindCompleteRunnables) { + runOnWorkerThread(r); + } + mBindCompleteRunnables.clear(); + } + } + // If we're profiling, ensure this is the last thing in the queue. if (DEBUG_LOADERS) { Log.d(TAG, "bound workspace in " + (SystemClock.uptimeMillis()-t) + "ms"); } - mIsLoadingAndBindingWorkspace = false; } }; if (isLoadingSynchronously) { @@ -2832,12 +2811,27 @@ public class LauncherModel extends BroadcastReceiver final ManagedProfileHeuristic heuristic = ManagedProfileHeuristic.get(mContext, user); if (heuristic != null) { - runAfterBindCompletes(new Runnable() { + final Runnable r = new Runnable() { @Override public void run() { heuristic.processUserApps(apps); } + }; + runOnMainThread(new Runnable() { + + @Override + public void run() { + // Check isLoadingWorkspace on the UI thread, as it is updated on + // the UI thread. + if (mIsLoadingAndBindingWorkspace) { + synchronized (mBindCompleteRunnables) { + mBindCompleteRunnables.add(r); + } + } else { + runOnWorkerThread(r); + } + } }); } } -- cgit v1.2.3 From d2eb49e4c3bb37d35e72c36d8a308262b690075f Mon Sep 17 00:00:00 2001 From: Winson Date: Tue, 18 Aug 2015 17:43:02 -0700 Subject: Tweaking fast scroller to follow touch closer. - Issue: The fast scroller currently does not follow the touch input because fundamentally, the fixed scrollbar height and the mapping of the scroll space to the scrollbar space is fundamentally incompatible. - This CL changes the fast scroller to allow it to detach when the user fast-scrolls, then re-attaches after the user scrolls the screen and the current scroll position for the scrollbar picks up the thumb position. - Since the scroll position and the fast scroller thumb is now detached, we can change the distribution of the fast scroll letters to make it independent of the rows for each section and instead uniformly distribute it along the scrollbar, which allows for more stability. - There are edge cases where this fails, especially when there are few apps, which we can investigate further. Bug: 20035978 Change-Id: I8322f862107e6f330deff692885233706564bffd --- proguard.flags | 4 +- src/com/android/launcher3/BaseRecyclerView.java | 40 +++++++------ .../launcher3/BaseRecyclerViewFastScrollBar.java | 38 ++++++++++-- .../launcher3/allapps/AllAppsContainerView.java | 3 +- .../launcher3/allapps/AllAppsRecyclerView.java | 68 +++++++++++++++++++--- .../launcher3/allapps/AlphabeticalAppsList.java | 59 ++++++++++++------- .../launcher3/widget/WidgetsRecyclerView.java | 12 ++-- 7 files changed, 162 insertions(+), 62 deletions(-) diff --git a/proguard.flags b/proguard.flags index a8e2b6092..b4365fee4 100644 --- a/proguard.flags +++ b/proguard.flags @@ -3,8 +3,8 @@ } -keep class com.android.launcher3.BaseRecyclerViewFastScrollBar { - public void setWidth(int); - public int getWidth(); + public void setThumbWidth(int); + public int getThumbWidth(); public void setTrackAlpha(int); public int getTrackAlpha(); } diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java index 0fae427e8..f0d8b3b3d 100644 --- a/src/com/android/launcher3/BaseRecyclerView.java +++ b/src/com/android/launcher3/BaseRecyclerView.java @@ -92,9 +92,15 @@ public abstract class BaseRecyclerView extends RecyclerView // TODO(winsonc): If we want to animate the section heads while scrolling, we can // initiate that here if the recycler view scroll state is not // RecyclerView.SCROLL_STATE_IDLE. + + onUpdateScrollbar(dy); } } + public void reset() { + mScrollbar.reattachThumbToScroll(); + } + @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -143,7 +149,7 @@ public abstract class BaseRecyclerView extends RecyclerView mScrollbar.handleTouchEvent(ev, mDownX, mDownY, mLastY); break; } - return mScrollbar.isDragging(); + return mScrollbar.isDraggingThumb(); } public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { @@ -185,12 +191,10 @@ public abstract class BaseRecyclerView extends RecyclerView * AvailableScrollHeight = Total height of the all items - last page height * * This assumes that all rows are the same height. - * - * @param yOffset the offset from the top of the recycler view to start tracking. */ - protected int getAvailableScrollHeight(int rowCount, int rowHeight, int yOffset) { + protected int getAvailableScrollHeight(int rowCount, int rowHeight) { int visibleHeight = getHeight() - mBackgroundPadding.top - mBackgroundPadding.bottom; - int scrollHeight = getPaddingTop() + yOffset + rowCount * rowHeight + getPaddingBottom(); + int scrollHeight = getPaddingTop() + rowCount * rowHeight + getPaddingBottom(); int availableScrollHeight = scrollHeight - visibleHeight; return availableScrollHeight; } @@ -222,7 +226,7 @@ public abstract class BaseRecyclerView extends RecyclerView @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); - onUpdateScrollbar(); + onUpdateScrollbar(0); mScrollbar.draw(canvas); } @@ -234,24 +238,21 @@ public abstract class BaseRecyclerView extends RecyclerView * @param scrollPosState the current scroll position * @param rowCount the number of rows, used to calculate the total scroll height (assumes that * all rows are the same height) - * @param yOffset the offset to start tracking in the recycler view (only used for all apps) */ protected void synchronizeScrollBarThumbOffsetToViewScroll(ScrollPositionState scrollPosState, - int rowCount, int yOffset) { - int availableScrollHeight = getAvailableScrollHeight(rowCount, scrollPosState.rowHeight, - yOffset); - int availableScrollBarHeight = getAvailableScrollBarHeight(); - + int rowCount) { // Only show the scrollbar if there is height to be scrolled + int availableScrollBarHeight = getAvailableScrollBarHeight(); + int availableScrollHeight = getAvailableScrollHeight(rowCount, scrollPosState.rowHeight); if (availableScrollHeight <= 0) { - mScrollbar.setScrollbarThumbOffset(-1, -1); + mScrollbar.setThumbOffset(-1, -1); return; } // Calculate the current scroll position, the scrollY of the recycler view accounts for the // view padding, while the scrollBarY is drawn right up to the background padding (ignoring // padding) - int scrollY = getPaddingTop() + yOffset + + int scrollY = getPaddingTop() + (scrollPosState.rowIndex * scrollPosState.rowHeight) - scrollPosState.rowTopOffset; int scrollBarY = mBackgroundPadding.top + (int) (((float) scrollY / availableScrollHeight) * availableScrollBarHeight); @@ -261,9 +262,9 @@ public abstract class BaseRecyclerView extends RecyclerView if (Utilities.isRtl(getResources())) { scrollBarX = mBackgroundPadding.left; } else { - scrollBarX = getWidth() - mBackgroundPadding.right - mScrollbar.getWidth(); + scrollBarX = getWidth() - mBackgroundPadding.right - mScrollbar.getThumbWidth(); } - mScrollbar.setScrollbarThumbOffset(scrollBarX, scrollBarY); + mScrollbar.setThumbOffset(scrollBarX, scrollBarY); } /** @@ -276,10 +277,15 @@ public abstract class BaseRecyclerView extends RecyclerView * Updates the bounds for the scrollbar. *

Override in each subclass of this base class. */ - public abstract void onUpdateScrollbar(); + public abstract void onUpdateScrollbar(int dy); /** *

Override in each subclass of this base class. */ public void onFastScrollCompleted() {} + + /** + * Returns information about the item that the recycler view is currently scrolled to. + */ + protected abstract void getCurScrollState(ScrollPositionState stateOut); } \ No newline at end of file diff --git a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java index 2c4184dc4..29e234d6c 100644 --- a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java +++ b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java @@ -56,9 +56,12 @@ public class BaseRecyclerViewFastScrollBar { private int mThumbMaxWidth; @Thunk int mThumbWidth; @Thunk int mThumbHeight; + private float mLastTouchY; // The inset is the buffer around which a point will still register as a click on the scrollbar private int mTouchInset; private boolean mIsDragging; + private boolean mIsThumbDetached; + private boolean mCanThumbDetach; // This is the offset from the top of the scrollbar when the user first starts touching. To // prevent jumping, this offset is applied as the user scrolls. @@ -84,7 +87,15 @@ public class BaseRecyclerViewFastScrollBar { mTouchInset = res.getDimensionPixelSize(R.dimen.container_fastscroll_thumb_touch_inset); } - public void setScrollbarThumbOffset(int x, int y) { + public void setDetachThumbOnFastScroll() { + mCanThumbDetach = true; + } + + public void reattachThumbToScroll() { + mIsThumbDetached = false; + } + + public void setThumbOffset(int x, int y) { if (mThumbOffset.x == x && mThumbOffset.y == y) { return; } @@ -95,8 +106,12 @@ public class BaseRecyclerViewFastScrollBar { mRv.invalidate(mInvalidateRect); } + public Point getThumbOffset() { + return mThumbOffset; + } + // Setter/getter for the search bar width for animations - public void setWidth(int width) { + public void setThumbWidth(int width) { mInvalidateRect.set(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, mRv.getHeight()); mThumbWidth = width; mInvalidateRect.union(new Rect(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, @@ -104,7 +119,7 @@ public class BaseRecyclerViewFastScrollBar { mRv.invalidate(mInvalidateRect); } - public int getWidth() { + public int getThumbWidth() { return mThumbWidth; } @@ -127,10 +142,18 @@ public class BaseRecyclerViewFastScrollBar { return mThumbMaxWidth; } - public boolean isDragging() { + public float getLastTouchY() { + return mLastTouchY; + } + + public boolean isDraggingThumb() { return mIsDragging; } + public boolean isThumbDetached() { + return mIsThumbDetached; + } + /** * Handles the touch event and determines whether to show the fast scroller (or updates it if * it is already showing). @@ -152,6 +175,9 @@ public class BaseRecyclerViewFastScrollBar { Math.abs(y - downY) > config.getScaledTouchSlop()) { mRv.getParent().requestDisallowInterceptTouchEvent(true); mIsDragging = true; + if (mCanThumbDetach) { + mIsThumbDetached = true; + } mTouchOffset += (lastY - downY); mPopup.animateVisibility(true); animateScrollbar(true); @@ -166,11 +192,13 @@ public class BaseRecyclerViewFastScrollBar { mPopup.setSectionName(sectionName); mPopup.animateVisibility(!sectionName.isEmpty()); mRv.invalidate(mPopup.updateFastScrollerBounds(mRv, lastY)); + mLastTouchY = boundedY; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: mTouchOffset = 0; + mLastTouchY = 0; if (mIsDragging) { mIsDragging = false; mPopup.animateVisibility(false); @@ -205,7 +233,7 @@ public class BaseRecyclerViewFastScrollBar { } ObjectAnimator trackAlphaAnim = ObjectAnimator.ofInt(this, "trackAlpha", isScrolling ? MAX_TRACK_ALPHA : 0); - ObjectAnimator thumbWidthAnim = ObjectAnimator.ofInt(this, "width", + ObjectAnimator thumbWidthAnim = ObjectAnimator.ofInt(this, "thumbWidth", isScrolling ? mThumbMaxWidth : mThumbMinWidth); ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), mThumbPaint.getColor(), isScrolling ? mThumbActiveColor : mThumbInactiveColor); diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index e129dc6d3..6d008ab98 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -555,8 +555,9 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc @Override public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) { if (toWorkspace) { - // Reset the search bar after transitioning home + // Reset the search bar and base recycler view after transitioning home mSearchBarController.reset(); + mAppsRecyclerView.reset(); } } diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java index 5aa973a15..5ec8bb258 100644 --- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java +++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java @@ -72,6 +72,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView public AllAppsRecyclerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr); + mScrollbar.setDetachThumbOnFastScroll(); } /** @@ -168,8 +169,8 @@ public class AllAppsRecyclerView extends BaseRecyclerView } // Map the touch position back to the scroll of the recycler view - getCurScrollState(mScrollPosState, mApps.getAdapterItems()); - int availableScrollHeight = getAvailableScrollHeight(rowCount, mScrollPosState.rowHeight, 0); + getCurScrollState(mScrollPosState); + int availableScrollHeight = getAvailableScrollHeight(rowCount, mScrollPosState.rowHeight); LinearLayoutManager layoutManager = (LinearLayoutManager) getLayoutManager(); if (mFastScrollMode == FAST_SCROLL_MODE_FREE_SCROLL) { layoutManager.scrollToPositionWithOffset(0, (int) -(availableScrollHeight * touchFraction)); @@ -216,24 +217,73 @@ public class AllAppsRecyclerView extends BaseRecyclerView * Updates the bounds for the scrollbar. */ @Override - public void onUpdateScrollbar() { + public void onUpdateScrollbar(int dy) { List items = mApps.getAdapterItems(); // Skip early if there are no items or we haven't been measured if (items.isEmpty() || mNumAppsPerRow == 0) { - mScrollbar.setScrollbarThumbOffset(-1, -1); + mScrollbar.setThumbOffset(-1, -1); return; } // Find the index and height of the first visible row (all rows have the same height) int rowCount = mApps.getNumAppRows(); - getCurScrollState(mScrollPosState, items); + getCurScrollState(mScrollPosState); if (mScrollPosState.rowIndex < 0) { - mScrollbar.setScrollbarThumbOffset(-1, -1); + mScrollbar.setThumbOffset(-1, -1); return; } - synchronizeScrollBarThumbOffsetToViewScroll(mScrollPosState, rowCount, 0); + // Only show the scrollbar if there is height to be scrolled + int availableScrollBarHeight = getAvailableScrollBarHeight(); + int availableScrollHeight = getAvailableScrollHeight(mApps.getNumAppRows(), mScrollPosState.rowHeight); + if (availableScrollHeight <= 0) { + mScrollbar.setThumbOffset(-1, -1); + return; + } + + // Calculate the current scroll position, the scrollY of the recycler view accounts for the + // view padding, while the scrollBarY is drawn right up to the background padding (ignoring + // padding) + int scrollY = getPaddingTop() + + (mScrollPosState.rowIndex * mScrollPosState.rowHeight) - mScrollPosState.rowTopOffset; + int scrollBarY = mBackgroundPadding.top + + (int) (((float) scrollY / availableScrollHeight) * availableScrollBarHeight); + + if (mScrollbar.isThumbDetached()) { + int scrollBarX; + if (Utilities.isRtl(getResources())) { + scrollBarX = mBackgroundPadding.left; + } else { + scrollBarX = getWidth() - mBackgroundPadding.right - mScrollbar.getThumbWidth(); + } + + if (mScrollbar.isDraggingThumb()) { + // If the thumb is detached, then just update the thumb to the current + // touch position + mScrollbar.setThumbOffset(scrollBarX, (int) mScrollbar.getLastTouchY()); + } else { + int thumbScrollY = mScrollbar.getThumbOffset().y; + int diffScrollY = scrollBarY - thumbScrollY; + if (diffScrollY * dy > 0f) { + // User is scrolling in the same direction the thumb needs to catch up to the + // current scroll position. + thumbScrollY += dy < 0 ? Math.max(dy, diffScrollY) : Math.min(dy, diffScrollY); + thumbScrollY = Math.max(0, Math.min(availableScrollBarHeight, thumbScrollY)); + mScrollbar.setThumbOffset(scrollBarX, thumbScrollY); + if (scrollBarY == thumbScrollY) { + mScrollbar.reattachThumbToScroll(); + } + } else { + // User is scrolling in an opposite direction to the direction that the thumb + // needs to catch up to the scroll position. Do nothing except for updating + // the scroll bar x to match the thumb width. + mScrollbar.setThumbOffset(scrollBarX, thumbScrollY); + } + } + } else { + synchronizeScrollBarThumbOffsetToViewScroll(mScrollPosState, rowCount); + } } /** @@ -285,13 +335,13 @@ public class AllAppsRecyclerView extends BaseRecyclerView /** * Returns the current scroll state of the apps rows. */ - private void getCurScrollState(ScrollPositionState stateOut, - List items) { + protected void getCurScrollState(ScrollPositionState stateOut) { stateOut.rowIndex = -1; stateOut.rowTopOffset = -1; stateOut.rowHeight = -1; // Return early if there are no items or we haven't been measured + List items = mApps.getAdapterItems(); if (items.isEmpty() || mNumAppsPerRow == 0) { return; } diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java index 396f75790..dac0df12a 100644 --- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java +++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java @@ -43,6 +43,11 @@ public class AlphabeticalAppsList { private static final boolean DEBUG = false; private static final boolean DEBUG_PREDICTIONS = false; + private static final int FAST_SCROLL_FRACTION_DISTRIBUTE_BY_ROWS_FRACTION = 0; + private static final int FAST_SCROLL_FRACTION_DISTRIBUTE_BY_NUM_SECTIONS = 1; + + private final int mFastScrollDistributionMode = FAST_SCROLL_FRACTION_DISTRIBUTE_BY_NUM_SECTIONS; + /** * Info about a section in the alphabetic list */ @@ -85,8 +90,6 @@ public class AlphabeticalAppsList { /** Section & App properties */ // The section for this item public SectionInfo sectionInfo; - // The row that this item shows up on - public int rowIndex; /** App-only properties */ // The section name of this app. Note that there can be multiple items with different @@ -94,6 +97,8 @@ public class AlphabeticalAppsList { public String sectionName = null; // The index of this app in the section public int sectionAppIndex = -1; + // The row that this item shows up on + public int rowIndex; // The index of this app in the row public int rowAppIndex; // The associated AppInfo for the app @@ -188,7 +193,6 @@ public class AlphabeticalAppsList { private int mNumAppsPerRow; private int mNumPredictedAppsPerRow; private int mNumAppRowsInAdapter; - private boolean mDisableEmptyText; public AlphabeticalAppsList(Context context) { mLauncher = (Launcher) context; @@ -215,13 +219,6 @@ public class AlphabeticalAppsList { mAdapter = adapter; } - /** - * Disables the empty text message when there are no search results. - */ - public void disableEmptyText() { - mDisableEmptyText = true; - } - /** * Returns all the apps. */ @@ -523,18 +520,36 @@ public class AlphabeticalAppsList { } mNumAppRowsInAdapter = rowIndex + 1; - // Pre-calculate all the fast scroller fractions based on the number of rows - float rowFraction = 1f / mNumAppRowsInAdapter; - for (FastScrollSectionInfo info : mFastScrollerSections) { - AdapterItem item = info.fastScrollToItem; - if (item.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE && - item.viewType != AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) { - info.touchFraction = 0f; - continue; - } - - float subRowFraction = item.rowAppIndex * (rowFraction / mNumAppsPerRow); - info.touchFraction = item.rowIndex * rowFraction + subRowFraction; + // Pre-calculate all the fast scroller fractions + switch (mFastScrollDistributionMode) { + case FAST_SCROLL_FRACTION_DISTRIBUTE_BY_ROWS_FRACTION: + float rowFraction = 1f / mNumAppRowsInAdapter; + for (FastScrollSectionInfo info : mFastScrollerSections) { + AdapterItem item = info.fastScrollToItem; + if (item.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE && + item.viewType != AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) { + info.touchFraction = 0f; + continue; + } + + float subRowFraction = item.rowAppIndex * (rowFraction / mNumAppsPerRow); + info.touchFraction = item.rowIndex * rowFraction + subRowFraction; + } + break; + case FAST_SCROLL_FRACTION_DISTRIBUTE_BY_NUM_SECTIONS: + float perSectionTouchFraction = 1f / mFastScrollerSections.size(); + float cumulativeTouchFraction = 0f; + for (FastScrollSectionInfo info : mFastScrollerSections) { + AdapterItem item = info.fastScrollToItem; + if (item.viewType != AllAppsGridAdapter.ICON_VIEW_TYPE && + item.viewType != AllAppsGridAdapter.PREDICTION_ICON_VIEW_TYPE) { + info.touchFraction = 0f; + continue; + } + info.touchFraction = cumulativeTouchFraction; + cumulativeTouchFraction += perSectionTouchFraction; + } + break; } } diff --git a/src/com/android/launcher3/widget/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/WidgetsRecyclerView.java index 61e63cdb7..e586dc253 100644 --- a/src/com/android/launcher3/widget/WidgetsRecyclerView.java +++ b/src/com/android/launcher3/widget/WidgetsRecyclerView.java @@ -102,7 +102,7 @@ public class WidgetsRecyclerView extends BaseRecyclerView { getCurScrollState(mScrollPosState); float pos = rowCount * touchFraction; - int availableScrollHeight = getAvailableScrollHeight(rowCount, mScrollPosState.rowHeight, 0); + int availableScrollHeight = getAvailableScrollHeight(rowCount, mScrollPosState.rowHeight); LinearLayoutManager layoutManager = ((LinearLayoutManager) getLayoutManager()); layoutManager.scrollToPositionWithOffset(0, (int) -(availableScrollHeight * touchFraction)); @@ -115,29 +115,29 @@ public class WidgetsRecyclerView extends BaseRecyclerView { * Updates the bounds for the scrollbar. */ @Override - public void onUpdateScrollbar() { + public void onUpdateScrollbar(int dy) { int rowCount = mWidgets.getPackageSize(); // Skip early if, there are no items. if (rowCount == 0) { - mScrollbar.setScrollbarThumbOffset(-1, -1); + mScrollbar.setThumbOffset(-1, -1); return; } // Skip early if, there no child laid out in the container. getCurScrollState(mScrollPosState); if (mScrollPosState.rowIndex < 0) { - mScrollbar.setScrollbarThumbOffset(-1, -1); + mScrollbar.setThumbOffset(-1, -1); return; } - synchronizeScrollBarThumbOffsetToViewScroll(mScrollPosState, rowCount, 0); + synchronizeScrollBarThumbOffsetToViewScroll(mScrollPosState, rowCount); } /** * Returns the current scroll state. */ - private void getCurScrollState(ScrollPositionState stateOut) { + protected void getCurScrollState(ScrollPositionState stateOut) { stateOut.rowIndex = -1; stateOut.rowTopOffset = -1; stateOut.rowHeight = -1; -- cgit v1.2.3 From 6779595bec64fa4503c22f75c8e245a449fe665d Mon Sep 17 00:00:00 2001 From: Winson Date: Thu, 20 Aug 2015 12:23:52 -0700 Subject: Updating the scrollbar to make the fastscroller more visible. Bug: 20035978 Change-Id: I56a865262cd07e6af11b4374a7e6354710116dcd --- proguard.flags | 4 +- res/values/colors.xml | 2 +- res/values/dimens.xml | 6 +- .../launcher3/BaseRecyclerViewFastScrollBar.java | 95 +++++++++++++++------- 4 files changed, 70 insertions(+), 37 deletions(-) diff --git a/proguard.flags b/proguard.flags index b4365fee4..e6c4c51c4 100644 --- a/proguard.flags +++ b/proguard.flags @@ -5,8 +5,8 @@ -keep class com.android.launcher3.BaseRecyclerViewFastScrollBar { public void setThumbWidth(int); public int getThumbWidth(); - public void setTrackAlpha(int); - public int getTrackAlpha(); + public void setTrackWidth(int); + public int getTrackWidth(); } -keep class com.android.launcher3.BaseRecyclerViewFastScrollPopup { diff --git a/res/values/colors.xml b/res/values/colors.xml index 0add48cd8..6fe2ae15d 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -39,7 +39,7 @@ #FFFFFFFF - #42000000 + #009688 #009688 diff --git a/res/values/dimens.xml b/res/values/dimens.xml index b9fb6e257..3f141513f 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -55,9 +55,9 @@ 4dp - 4dp - 8dp - 64dp + 5dp + 9dp + 72dp -24dp 72dp 48dp diff --git a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java index 29e234d6c..f76aed7ad 100644 --- a/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java +++ b/src/com/android/launcher3/BaseRecyclerViewFastScrollBar.java @@ -23,6 +23,7 @@ import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Path; import android.graphics.Point; import android.graphics.Rect; import android.view.MotionEvent; @@ -51,11 +52,14 @@ public class BaseRecyclerViewFastScrollBar { private int mThumbActiveColor; @Thunk Point mThumbOffset = new Point(-1, -1); @Thunk Paint mThumbPaint; - private Paint mTrackPaint; private int mThumbMinWidth; private int mThumbMaxWidth; @Thunk int mThumbWidth; @Thunk int mThumbHeight; + private int mThumbCurvature; + private Path mThumbPath = new Path(); + private Paint mTrackPaint; + private int mTrackWidth; private float mLastTouchY; // The inset is the buffer around which a point will still register as a click on the scrollbar private int mTouchInset; @@ -75,15 +79,18 @@ public class BaseRecyclerViewFastScrollBar { mPopup = new BaseRecyclerViewFastScrollPopup(rv, res); mTrackPaint = new Paint(); mTrackPaint.setColor(rv.getFastScrollerTrackColor(Color.BLACK)); - mTrackPaint.setAlpha(0); + mTrackPaint.setAlpha(MAX_TRACK_ALPHA); mThumbInactiveColor = rv.getFastScrollerThumbInactiveColor( res.getColor(R.color.container_fastscroll_thumb_inactive_color)); mThumbActiveColor = res.getColor(R.color.container_fastscroll_thumb_active_color); mThumbPaint = new Paint(); + mThumbPaint.setAntiAlias(true); mThumbPaint.setColor(mThumbInactiveColor); + mThumbPaint.setStyle(Paint.Style.FILL); mThumbWidth = mThumbMinWidth = res.getDimensionPixelSize(R.dimen.container_fastscroll_thumb_min_width); mThumbMaxWidth = res.getDimensionPixelSize(R.dimen.container_fastscroll_thumb_max_width); mThumbHeight = res.getDimensionPixelSize(R.dimen.container_fastscroll_thumb_height); + mThumbCurvature = mThumbMaxWidth - mThumbMinWidth; mTouchInset = res.getDimensionPixelSize(R.dimen.container_fastscroll_thumb_touch_inset); } @@ -99,10 +106,12 @@ public class BaseRecyclerViewFastScrollBar { if (mThumbOffset.x == x && mThumbOffset.y == y) { return; } - mInvalidateRect.set(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, mRv.getHeight()); + mInvalidateRect.set(mThumbOffset.x - mThumbCurvature, mThumbOffset.y, + mThumbOffset.x + mThumbWidth, mThumbOffset.y + mThumbHeight); mThumbOffset.set(x, y); - mInvalidateRect.union(new Rect(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, - mRv.getHeight())); + updateThumbPath(); + mInvalidateRect.union(mThumbOffset.x - mThumbCurvature, mThumbOffset.y, + mThumbOffset.x + mThumbWidth, mThumbOffset.y + mThumbHeight); mRv.invalidate(mInvalidateRect); } @@ -110,12 +119,14 @@ public class BaseRecyclerViewFastScrollBar { return mThumbOffset; } - // Setter/getter for the search bar width for animations + // Setter/getter for the thumb bar width for animations public void setThumbWidth(int width) { - mInvalidateRect.set(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, mRv.getHeight()); + mInvalidateRect.set(mThumbOffset.x - mThumbCurvature, mThumbOffset.y, + mThumbOffset.x + mThumbWidth, mThumbOffset.y + mThumbHeight); mThumbWidth = width; - mInvalidateRect.union(new Rect(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, - mRv.getHeight())); + updateThumbPath(); + mInvalidateRect.union(mThumbOffset.x - mThumbCurvature, mThumbOffset.y, + mThumbOffset.x + mThumbWidth, mThumbOffset.y + mThumbHeight); mRv.invalidate(mInvalidateRect); } @@ -123,15 +134,19 @@ public class BaseRecyclerViewFastScrollBar { return mThumbWidth; } - // Setter/getter for the track background alpha for animations - public void setTrackAlpha(int alpha) { - mTrackPaint.setAlpha(alpha); - mInvalidateRect.set(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, mRv.getHeight()); + // Setter/getter for the track bar width for animations + public void setTrackWidth(int width) { + mInvalidateRect.set(mThumbOffset.x - mThumbCurvature, 0, mThumbOffset.x + mThumbWidth, + mRv.getHeight()); + mTrackWidth = width; + updateThumbPath(); + mInvalidateRect.union(mThumbOffset.x - mThumbCurvature, 0, mThumbOffset.x + mThumbWidth, + mRv.getHeight()); mRv.invalidate(mInvalidateRect); } - public int getTrackAlpha() { - return mTrackPaint.getAlpha(); + public int getTrackWidth() { + return mTrackWidth; } public int getThumbHeight() { @@ -217,8 +232,7 @@ public class BaseRecyclerViewFastScrollBar { if (mTrackPaint.getAlpha() > 0) { canvas.drawRect(mThumbOffset.x, 0, mThumbOffset.x + mThumbWidth, mRv.getHeight(), mTrackPaint); } - canvas.drawRect(mThumbOffset.x, mThumbOffset.y, mThumbOffset.x + mThumbWidth, - mThumbOffset.y + mThumbHeight, mThumbPaint); + canvas.drawPath(mThumbPath, mThumbPaint); // Draw the popup mPopup.draw(canvas); @@ -231,26 +245,45 @@ public class BaseRecyclerViewFastScrollBar { if (mScrollbarAnimator != null) { mScrollbarAnimator.cancel(); } - ObjectAnimator trackAlphaAnim = ObjectAnimator.ofInt(this, "trackAlpha", - isScrolling ? MAX_TRACK_ALPHA : 0); + + mScrollbarAnimator = new AnimatorSet(); + ObjectAnimator trackWidthAnim = ObjectAnimator.ofInt(this, "trackWidth", + isScrolling ? mThumbMaxWidth : mThumbMinWidth); ObjectAnimator thumbWidthAnim = ObjectAnimator.ofInt(this, "thumbWidth", isScrolling ? mThumbMaxWidth : mThumbMinWidth); - ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), - mThumbPaint.getColor(), isScrolling ? mThumbActiveColor : mThumbInactiveColor); - colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animator) { - mThumbPaint.setColor((Integer) animator.getAnimatedValue()); - mRv.invalidate(mThumbOffset.x, mThumbOffset.y, mThumbOffset.x + mThumbWidth, - mThumbOffset.y + mThumbHeight); - } - }); - mScrollbarAnimator = new AnimatorSet(); - mScrollbarAnimator.playTogether(trackAlphaAnim, thumbWidthAnim, colorAnimation); + mScrollbarAnimator.playTogether(trackWidthAnim, thumbWidthAnim); + if (mThumbActiveColor != mThumbInactiveColor) { + ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), + mThumbPaint.getColor(), isScrolling ? mThumbActiveColor : mThumbInactiveColor); + colorAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animator) { + mThumbPaint.setColor((Integer) animator.getAnimatedValue()); + mRv.invalidate(mThumbOffset.x, mThumbOffset.y, mThumbOffset.x + mThumbWidth, + mThumbOffset.y + mThumbHeight); + } + }); + mScrollbarAnimator.play(colorAnimation); + } mScrollbarAnimator.setDuration(SCROLL_BAR_VIS_DURATION); mScrollbarAnimator.start(); } + /** + * Updates the path for the thumb drawable. + */ + private void updateThumbPath() { + mThumbCurvature = mThumbMaxWidth - mThumbWidth; + mThumbPath.reset(); + mThumbPath.moveTo(mThumbOffset.x + mThumbWidth, mThumbOffset.y); // tr + mThumbPath.lineTo(mThumbOffset.x + mThumbWidth, mThumbOffset.y + mThumbHeight); // br + mThumbPath.lineTo(mThumbOffset.x, mThumbOffset.y + mThumbHeight); // bl + mThumbPath.cubicTo(mThumbOffset.x, mThumbOffset.y + mThumbHeight, + mThumbOffset.x - mThumbCurvature, mThumbOffset.y + mThumbHeight / 2, + mThumbOffset.x, mThumbOffset.y); // bl2tl + mThumbPath.close(); + } + /** * Returns whether the specified points are near the scroll bar bounds. */ -- cgit v1.2.3 From 81c5f7e39727085e1a8915cc36e9cbf2bb085890 Mon Sep 17 00:00:00 2001 From: Winson Date: Thu, 20 Aug 2015 15:22:18 -0700 Subject: Fixing issue with search bar not being visible. - If you queue up two SearchBarDropTarget state transitions one right after another, the second animation will skip (since the values haven't started animating yet) and the first animation will complete instead, leaving the visibility of the search and drop target bars at odds with the current bar state. - Instead, we should cancel all existing animators first, such that if we are already in the final state, no animations will run, and the correct bars will be visibile. Bug: 23201830 Change-Id: I1f8e802821ef2b4904a3efa7edbea6ae615479b9 --- src/com/android/launcher3/SearchDropTargetBar.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/SearchDropTargetBar.java b/src/com/android/launcher3/SearchDropTargetBar.java index 1efdfb62d..772a334b9 100644 --- a/src/com/android/launcher3/SearchDropTargetBar.java +++ b/src/com/android/launcher3/SearchDropTargetBar.java @@ -186,7 +186,12 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D */ private void animateViewAlpha(LauncherViewPropertyAnimator animator, View v, float alpha, int duration) { - if (v != null && Float.compare(v.getAlpha(), alpha) != 0) { + if (v == null) { + return; + } + + animator.cancel(); + if (Float.compare(v.getAlpha(), alpha) != 0) { if (duration > 0) { animator.alpha(alpha).withLayer().setDuration(duration).start(); } else { -- cgit v1.2.3 From ad0c2f28ceb750646e0132a01d393f5115cbfca9 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 21 Aug 2015 09:23:44 -0700 Subject: Using the usermanager api to get creation time Bug: 22539048 Change-Id: I17647f2456434ca66a9778300e1a2910cec171d4 --- src/com/android/launcher3/compat/UserManagerCompatVL.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/compat/UserManagerCompatVL.java b/src/com/android/launcher3/compat/UserManagerCompatVL.java index 4d404db2b..dc3ec3cd8 100644 --- a/src/com/android/launcher3/compat/UserManagerCompatVL.java +++ b/src/com/android/launcher3/compat/UserManagerCompatVL.java @@ -26,6 +26,7 @@ import android.os.Build; import android.os.UserHandle; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.Utilities; import com.android.launcher3.util.LongArrayMap; import java.util.ArrayList; @@ -100,7 +101,9 @@ public class UserManagerCompatVL extends UserManagerCompatV17 { @Override public long getUserCreationTime(UserHandleCompat user) { - // TODO: Use system API once available. + if (Utilities.ATLEAST_MARSHMALLOW) { + return mUserManager.getUserCreationTime(user.getUser()); + } SharedPreferences prefs = mContext.getSharedPreferences( LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE); String key = USER_CREATION_TIME_KEY + getSerialNumberForUser(user); -- cgit v1.2.3 From 830b5e08ef8ccc8e4193926ac10ac38cb0ae3e56 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 21 Aug 2015 09:26:10 -0700 Subject: Updating the target sdk to launcher Change-Id: Icf8e22f6ceb57dcd4e101b8b1d3ae86c52d12b30 --- AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 3af38f384..99a6ad9aa 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -20,7 +20,7 @@ - + Date: Thu, 20 Aug 2015 16:17:36 -0700 Subject: Updating theme to use the light theme by default, instead of wallpaper theme > This allows us to use all the goodness of material theme > Cursor in folder edit text is no longer 1px wide Change-Id: I705f5472ff71969ae45747dd127a8ba5253df44d --- WallpaperPicker/res/values-v19/styles.xml | 2 +- WallpaperPicker/res/values-v21/styles.xml | 7 +++++++ WallpaperPicker/res/values/colors.xml | 2 ++ WallpaperPicker/res/values/styles.xml | 8 +++++++- res/layout/all_apps_search_market.xml | 2 +- res/layout/overview_panel.xml | 3 +++ res/layout/user_folder.xml | 1 - 7 files changed, 21 insertions(+), 4 deletions(-) diff --git a/WallpaperPicker/res/values-v19/styles.xml b/WallpaperPicker/res/values-v19/styles.xml index 136cf012c..15fb0ea2a 100644 --- a/WallpaperPicker/res/values-v19/styles.xml +++ b/WallpaperPicker/res/values-v19/styles.xml @@ -25,7 +25,7 @@ true - diff --git a/WallpaperPicker/res/values-v21/styles.xml b/WallpaperPicker/res/values-v21/styles.xml index 582ab8fed..70220edb9 100644 --- a/WallpaperPicker/res/values-v21/styles.xml +++ b/WallpaperPicker/res/values-v21/styles.xml @@ -33,4 +33,11 @@ ?android:attr/selectableItemBackgroundBorderless + \ No newline at end of file diff --git a/WallpaperPicker/res/values/colors.xml b/WallpaperPicker/res/values/colors.xml index adae7cff6..6ba32f06d 100644 --- a/WallpaperPicker/res/values/colors.xml +++ b/WallpaperPicker/res/values/colors.xml @@ -19,4 +19,6 @@ --> #66000000 + + #ff009688 diff --git a/WallpaperPicker/res/values/styles.xml b/WallpaperPicker/res/values/styles.xml index 74aeab903..d1c945a32 100644 --- a/WallpaperPicker/res/values/styles.xml +++ b/WallpaperPicker/res/values/styles.xml @@ -35,9 +35,15 @@ #88000000 - + +