From dfb5cc9a09d5d8639fbccf76540e4182b8a0cdf9 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Mon, 26 Feb 2018 16:41:57 -0800 Subject: [PATCH 001/127] Flip recents if setting is true Bug: 72860694 Change-Id: I5cb71f553b2833a18a1b419b3744175bff963da8 --- .../LauncherAppTransitionManagerImpl.java | 11 ++++---- .../launcher3/uioverrides/OverviewState.java | 3 +-- .../com/android/quickstep/RecentsView.java | 26 +++++++++++++++++-- src/com/android/launcher3/PagedView.java | 2 +- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index 8f498d27fe..5da53f2eb8 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -259,6 +259,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag int launchedTaskIndex = recentsView.indexOfChild(v); int centerTaskIndex = recentsView.getCurrentPage(); boolean launchingCenterTask = launchedTaskIndex == centerTaskIndex; + boolean isRtl = recentsView.isRtl(); if (launchingCenterTask) { if (launchedTaskIndex - 1 >= recentsView.getFirstTaskIndex()) { TaskView adjacentPage1 = (TaskView) recentsView.getPageAt(launchedTaskIndex - 1); @@ -267,7 +268,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag new PropertyListBuilder() .scale(adjacentPage1.getScaleX() * mRecentsScale) .translationY(mRecentsTransY) - .translationX(mIsRtl ? mRecentsTransX : -mRecentsTransX) + .translationX(isRtl ? mRecentsTransX : -mRecentsTransX) .build()); launcherAnimator.play(adjacentTask1ScaleAndTranslate); } @@ -278,7 +279,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag new PropertyListBuilder() .scale(adjacentTask2.getScaleX() * mRecentsScale) .translationY(mRecentsTransY) - .translationX(mIsRtl ? -mRecentsTransX : mRecentsTransX) + .translationX(isRtl ? -mRecentsTransX : mRecentsTransX) .build()); launcherAnimator.play(adjacentTask2ScaleAndTranslate); } @@ -290,7 +291,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag LauncherAnimUtils.ofPropertyValuesHolder(centerTask, new PropertyListBuilder() .scale(v.getScaleX()) - .translationX(mIsRtl ? -translationX : translationX) + .translationX(isRtl ? -translationX : translationX) .build()); launcherAnimator.play(centerTaskParallaxToRight); int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - launchedTaskIndex); @@ -302,7 +303,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag LauncherAnimUtils.ofPropertyValuesHolder(otherAdjacentTask, new PropertyListBuilder() .translationX(otherAdjacentTask.getTranslationX() - + (mIsRtl ? -translationX : translationX)) + + (isRtl ? -translationX : translationX)) .build()); launcherAnimator.play(otherAdjacentTaskParallaxToRight); } @@ -745,7 +746,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag Matrix matrix = new Matrix(); float height = mLauncher.getDeviceProfile().heightPx; float width = mLauncher.getDeviceProfile().widthPx; - float endX = (Utilities.isRtl(mLauncher.getResources()) ? -width : width) * 1.16f; + float endX = (mLauncher.getOverviewPanel().isRtl() ? -width : width) * 1.16f; ValueAnimator closingAnimator = ValueAnimator.ofFloat(0, 1); closingAnimator.setDuration(CLOSING_TRANSITION_DURATION_MS); diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java index 9ba2308c62..613968ecd8 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java @@ -26,7 +26,6 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; -import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.quickstep.RecentsView; @@ -111,7 +110,7 @@ public class OverviewState extends LauncherState { scale * (halfWidth - ws.getPaddingLeft() - insets.left - childWidth / 2); float translationX = pageRect.centerX() - childCenter; - if (Utilities.isRtl(launcher.getResources())) { + if (launcher.getOverviewPanel().isRtl()) { translationX -= offsetX / scale; } else { translationX += offsetX / scale; diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java index ec0716c49c..9e07b4977f 100644 --- a/quickstep/src/com/android/quickstep/RecentsView.java +++ b/quickstep/src/com/android/quickstep/RecentsView.java @@ -23,6 +23,8 @@ import static com.android.quickstep.TaskView.CURVE_INTERPOLATOR; import android.animation.LayoutTransition; import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; @@ -62,7 +64,7 @@ import java.util.ArrayList; /** * A list of recent tasks. */ -public class RecentsView extends PagedView implements Insettable { +public class RecentsView extends PagedView implements Insettable, OnSharedPreferenceChangeListener { private static final Rect sTempStableInsets = new Rect(); @@ -70,6 +72,8 @@ public class RecentsView extends PagedView implements Insettable { public static final int SCROLL_TYPE_TASK = 1; public static final int SCROLL_TYPE_WORKSPACE = 2; + private static final String PREF_FLIP_RECENTS = "pref_flip_recents"; + private final Launcher mLauncher; private QuickScrubController mQuickScrubController; private final ScrollState mScrollState = new ScrollState(); @@ -130,7 +134,23 @@ public class RecentsView extends PagedView implements Insettable { mQuickScrubController = new QuickScrubController(mLauncher, this); mModel = RecentsModel.getInstance(context); - mScrollState.isRtl = mIsRtl; + onSharedPreferenceChanged(Utilities.getPrefs(context), PREF_FLIP_RECENTS); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) { + if (s.equals(PREF_FLIP_RECENTS)) { + mIsRtl = Utilities.isRtl(getResources()); + if (sharedPreferences.getBoolean(PREF_FLIP_RECENTS, false)) { + mIsRtl = !mIsRtl; + } + setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR); + mScrollState.isRtl = mIsRtl; + } + } + + public boolean isRtl() { + return mIsRtl; } public TaskView updateThumbnail(int taskId, ThumbnailData thumbnailData) { @@ -172,12 +192,14 @@ public class RecentsView extends PagedView implements Insettable { protected void onAttachedToWindow() { super.onAttachedToWindow(); updateTaskStackListenerState(); + Utilities.getPrefs(getContext()).registerOnSharedPreferenceChangeListener(this); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); updateTaskStackListenerState(); + Utilities.getPrefs(getContext()).unregisterOnSharedPreferenceChangeListener(this); } @Override diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index ccb0a955d3..15961ad539 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -182,7 +182,7 @@ public abstract class PagedView extends ViewGrou private static final Rect sTmpRect = new Rect(); protected final Rect mInsets = new Rect(); - protected final boolean mIsRtl; + protected boolean mIsRtl; // Similar to the platform implementation of isLayoutValid(); protected boolean mIsLayoutValid; From 1b6826c53c91eea4e7635c2306cc6bbcf65431bd Mon Sep 17 00:00:00 2001 From: Tony Mak Date: Tue, 27 Feb 2018 15:06:12 +0000 Subject: [PATCH 002/127] Deprecate work folder FIX: 73876183 Change-Id: I9d15df247eed3500c679cba085c680b75581cffb --- .../android/launcher3/LauncherProvider.java | 7 +- .../launcher3/SessionCommitReceiver.java | 8 +- .../launcher3/compat/UserManagerCompat.java | 1 - .../launcher3/compat/UserManagerCompatVL.java | 11 - .../launcher3/compat/UserManagerCompatVM.java | 5 - .../model/AddWorkspaceItemsTask.java | 24 -- .../android/launcher3/model/LoaderTask.java | 3 - .../util/ManagedProfileHeuristic.java | 254 ------------------ .../launcher3/ui/AbstractLauncherUiTest.java | 13 +- 9 files changed, 8 insertions(+), 318 deletions(-) delete mode 100644 src/com/android/launcher3/util/ManagedProfileHeuristic.java diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index 138ea0f650..cf984c0a55 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -59,7 +59,6 @@ import com.android.launcher3.model.DbDowngradeHelper; import com.android.launcher3.provider.LauncherDbUtils; import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction; import com.android.launcher3.provider.RestoreDbTask; -import com.android.launcher3.util.ManagedProfileHeuristic; import com.android.launcher3.util.NoLocaleSqliteContext; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.Thunk; @@ -623,10 +622,6 @@ public class LauncherProvider extends ContentProvider { // Set the flag for empty DB Utilities.getPrefs(mContext).edit().putBoolean(EMPTY_DATABASE_CREATED, true).commit(); - - // When a new DB is created, remove all previously stored managed profile information. - ManagedProfileHeuristic.processAllUsers(Collections.emptyList(), - mContext); } public long getDefaultUserSerial() { @@ -790,7 +785,7 @@ public class LauncherProvider extends ContentProvider { case 23: // No-op case 24: - ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mContext); + // No-op case 25: convertShortcutsToLauncherActivities(db); case 26: diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java index edb7ff533c..b0da6b9cd9 100644 --- a/src/com/android/launcher3/SessionCommitReceiver.java +++ b/src/com/android/launcher3/SessionCommitReceiver.java @@ -67,11 +67,9 @@ public class SessionCommitReceiver extends BroadcastReceiver { SessionInfo info = intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION); UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER); - if (Process.myUserHandle().equals(user)) { - if (TextUtils.isEmpty(info.getAppPackageName()) || - info.getInstallReason() != PackageManager.INSTALL_REASON_USER) { - return; - } + if (TextUtils.isEmpty(info.getAppPackageName()) || + info.getInstallReason() != PackageManager.INSTALL_REASON_USER) { + return; } queueAppIconAddition(context, info.getAppPackageName(), user); diff --git a/src/com/android/launcher3/compat/UserManagerCompat.java b/src/com/android/launcher3/compat/UserManagerCompat.java index 62055dc49a..03e3861eae 100644 --- a/src/com/android/launcher3/compat/UserManagerCompat.java +++ b/src/com/android/launcher3/compat/UserManagerCompat.java @@ -58,7 +58,6 @@ public abstract class UserManagerCompat { public abstract long getSerialNumberForUser(UserHandle user); public abstract UserHandle getUserForSerialNumber(long serialNumber); public abstract CharSequence getBadgedLabelForUser(CharSequence label, UserHandle user); - public abstract long getUserCreationTime(UserHandle user); public abstract boolean isQuietModeEnabled(UserHandle user); public abstract boolean isUserUnlocked(UserHandle user); diff --git a/src/com/android/launcher3/compat/UserManagerCompatVL.java b/src/com/android/launcher3/compat/UserManagerCompatVL.java index e57786d8cb..1ff69818a9 100644 --- a/src/com/android/launcher3/compat/UserManagerCompatVL.java +++ b/src/com/android/launcher3/compat/UserManagerCompatVL.java @@ -23,7 +23,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.util.ArrayMap; import com.android.launcher3.util.LongArrayMap; -import com.android.launcher3.util.ManagedProfileHeuristic; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -127,15 +126,5 @@ public class UserManagerCompatVL extends UserManagerCompat { } return mPm.getUserBadgedLabel(label, user); } - - @Override - public long getUserCreationTime(UserHandle user) { - SharedPreferences prefs = ManagedProfileHeuristic.prefs(mContext); - String key = USER_CREATION_TIME_KEY + getSerialNumberForUser(user); - if (!prefs.contains(key)) { - prefs.edit().putLong(key, System.currentTimeMillis()).apply(); - } - return prefs.getLong(key, 0); - } } diff --git a/src/com/android/launcher3/compat/UserManagerCompatVM.java b/src/com/android/launcher3/compat/UserManagerCompatVM.java index 75c1877139..cf74b37279 100644 --- a/src/com/android/launcher3/compat/UserManagerCompatVM.java +++ b/src/com/android/launcher3/compat/UserManagerCompatVM.java @@ -27,9 +27,4 @@ public class UserManagerCompatVM extends UserManagerCompatVL { UserManagerCompatVM(Context context) { super(context); } - - @Override - public long getUserCreationTime(UserHandle user) { - return mUserManager.getUserCreationTime(user); - } } diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java index a33a039c0e..fefe07d9be 100644 --- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java +++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java @@ -17,10 +17,7 @@ package com.android.launcher3.model; import android.content.Context; import android.content.Intent; -import android.content.pm.LauncherActivityInfo; -import android.os.Process; import android.os.UserHandle; -import android.util.ArrayMap; import android.util.LongSparseArray; import android.util.Pair; import com.android.launcher3.AllAppsList; @@ -37,7 +34,6 @@ import com.android.launcher3.LauncherSettings; import com.android.launcher3.ShortcutInfo; import com.android.launcher3.Utilities; import com.android.launcher3.util.GridOccupancy; -import com.android.launcher3.util.ManagedProfileHeuristic.UserFolderInfo; import java.util.ArrayList; import java.util.List; @@ -64,7 +60,6 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask { final ArrayList addedItemsFinal = new ArrayList<>(); final ArrayList addedWorkspaceScreensFinal = new ArrayList<>(); - ArrayMap userFolderMap = new ArrayMap<>(); // Get the list of workspace screens. We need to append to this list and // can not use sBgWorkspaceScreens because loadWorkspace() may not have been @@ -87,21 +82,6 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask { if (item instanceof AppInfo) { item = ((AppInfo) item).makeShortcut(); } - - if (!Process.myUserHandle().equals(item.user)) { - // Check if this belongs to a work folder. - if (!(entry.second instanceof LauncherActivityInfo)) { - continue; - } - - UserFolderInfo userFolderInfo = userFolderMap.get(item.user); - if (userFolderInfo == null) { - userFolderInfo = new UserFolderInfo(context, item.user, dataModel); - userFolderMap.put(item.user, userFolderInfo); - } - item = userFolderInfo.convertToWorkspaceItem( - (ShortcutInfo) item, (LauncherActivityInfo) entry.second); - } } if (item != null) { filteredItems.add(item); @@ -160,10 +140,6 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask { } }); } - - for (UserFolderInfo userFolderInfo : userFolderMap.values()) { - userFolderInfo.applyPendingState(getModelWriter()); - } } protected void updateScreens(Context context, ArrayList workspaceScreens) { diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 00dd3aac61..c61505014b 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -62,7 +62,6 @@ import com.android.launcher3.shortcuts.ShortcutInfoCompat; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.LooperIdleLock; -import com.android.launcher3.util.ManagedProfileHeuristic; import com.android.launcher3.util.MultiHashMap; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.Provider; @@ -812,8 +811,6 @@ public class LoaderTask implements Runnable { // This builds the icon bitmaps. mBgAllAppsList.add(new AppInfo(app, user, quietMode), app); } - - ManagedProfileHeuristic.onAllAppsLoaded(mApp.getContext(), apps, user); } if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS) { diff --git a/src/com/android/launcher3/util/ManagedProfileHeuristic.java b/src/com/android/launcher3/util/ManagedProfileHeuristic.java deleted file mode 100644 index 009aee775c..0000000000 --- a/src/com/android/launcher3/util/ManagedProfileHeuristic.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3.util; - -import android.content.Context; -import android.content.SharedPreferences; -import android.content.pm.LauncherActivityInfo; -import android.os.Handler; -import android.os.Process; -import android.os.UserHandle; - -import com.android.launcher3.FolderInfo; -import com.android.launcher3.InstallShortcutReceiver; -import com.android.launcher3.ItemInfo; -import com.android.launcher3.LauncherFiles; -import com.android.launcher3.LauncherModel; -import com.android.launcher3.MainThreadExecutor; -import com.android.launcher3.R; -import com.android.launcher3.SessionCommitReceiver; -import com.android.launcher3.ShortcutInfo; -import com.android.launcher3.Utilities; -import com.android.launcher3.compat.UserManagerCompat; -import com.android.launcher3.model.BgDataModel; -import com.android.launcher3.model.ModelWriter; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; - -/** - * Handles addition of app shortcuts for managed profiles. - * Methods of class should only be called on {@link LauncherModel#sWorkerThread}. - */ -public class ManagedProfileHeuristic { - - private static final String USER_FOLDER_ID_PREFIX = "user_folder_"; - - /** - * Duration (in milliseconds) for which app shortcuts will be added to work folder. - */ - private static final long AUTO_ADD_TO_FOLDER_DURATION = 8 * 60 * 60 * 1000; - - public static void onAllAppsLoaded(final Context context, - List apps, UserHandle user) { - if (Process.myUserHandle().equals(user)) { - return; - } - - UserFolderInfo ufi = new UserFolderInfo(context, user, null); - // We only handle folder creation once. Later icon additions are handled using package - // or session events. - if (ufi.folderAlreadyCreated) { - return; - } - - if (Utilities.ATLEAST_OREO && !SessionCommitReceiver.isEnabled(context)) { - // Just mark the folder id preference to avoid new folder creation later. - ufi.prefs.edit().putLong(ufi.folderIdKey, ItemInfo.NO_ID).apply(); - return; - } - - InstallShortcutReceiver.enableInstallQueue(InstallShortcutReceiver.FLAG_BULK_ADD); - for (LauncherActivityInfo app : apps) { - // Queue all items which should go in the work folder. - if (app.getFirstInstallTime() < ufi.addIconToFolderTime) { - InstallShortcutReceiver.queueActivityInfo(app, context); - } - } - // Post the queue update on next frame, so that the loader gets finished. - new Handler(LauncherModel.getWorkerLooper()).post(new Runnable() { - @Override - public void run() { - InstallShortcutReceiver.disableAndFlushInstallQueue( - InstallShortcutReceiver.FLAG_BULK_ADD, context); - } - }); - } - - - /** - * Utility class to help workspace icon addition. - */ - public static class UserFolderInfo { - - final ArrayList pendingShortcuts = new ArrayList<>(); - - final UserHandle user; - - final long userSerial; - // Time until which icons will be added to folder instead. - final long addIconToFolderTime; - - final String folderIdKey; - final SharedPreferences prefs; - - final boolean folderAlreadyCreated; - final FolderInfo folderInfo; - - boolean folderPendingAddition; - - public UserFolderInfo(Context context, UserHandle user, BgDataModel dataModel) { - this.user = user; - - UserManagerCompat um = UserManagerCompat.getInstance(context); - userSerial = um.getSerialNumberForUser(user); - addIconToFolderTime = um.getUserCreationTime(user) + AUTO_ADD_TO_FOLDER_DURATION; - - folderIdKey = USER_FOLDER_ID_PREFIX + userSerial; - prefs = prefs(context); - - folderAlreadyCreated = prefs.contains(folderIdKey); - if (dataModel != null) { - if (folderAlreadyCreated) { - long folderId = prefs.getLong(folderIdKey, ItemInfo.NO_ID); - folderInfo = dataModel.folders.get(folderId); - } else { - folderInfo = new FolderInfo(); - folderInfo.title = context.getText(R.string.work_folder_name); - folderInfo.setOption(FolderInfo.FLAG_WORK_FOLDER, true, null); - folderPendingAddition = true; - } - } else { - folderInfo = null; - } - } - - /** - * Returns the ItemInfo which should be added to the workspace. In case the the provided - * {@link ShortcutInfo} or a wrapped {@link FolderInfo} or null. - */ - public ItemInfo convertToWorkspaceItem( - ShortcutInfo shortcut, LauncherActivityInfo activityInfo) { - if (activityInfo.getFirstInstallTime() >= addIconToFolderTime) { - return shortcut; - } - - if (folderAlreadyCreated) { - if (folderInfo == null) { - // Work folder was deleted by user, add icon to home screen. - return shortcut; - } else { - // Add item to work folder instead. Nothing needs to be added - // on the homescreen. - pendingShortcuts.add(shortcut); - return null; - } - } - - pendingShortcuts.add(shortcut); - folderInfo.add(shortcut, false); - if (folderPendingAddition) { - folderPendingAddition = false; - return folderInfo; - } else { - // WorkFolder already requested to be added. Nothing new needs to be added. - return null; - } - } - - public void applyPendingState(ModelWriter writer) { - if (folderInfo == null) { - return; - } - - int startingRank = 0; - if (folderAlreadyCreated) { - startingRank = folderInfo.contents.size(); - } - - for (ShortcutInfo info : pendingShortcuts) { - info.rank = startingRank++; - writer.addItemToDatabase(info, folderInfo.id, 0, 0, 0); - } - - if (folderAlreadyCreated) { - // FolderInfo could already be bound. We need to add shortcuts on the UI thread. - new MainThreadExecutor().execute(new Runnable() { - - @Override - public void run() { - folderInfo.prepareAutoUpdate(); - for (ShortcutInfo info : pendingShortcuts) { - folderInfo.add(info, false); - } - } - }); - } else { - prefs.edit().putLong(folderIdKey, folderInfo.id).apply(); - } - } - } - - /** - * Verifies that entries corresponding to {@param users} exist and removes all invalid entries. - */ - public static void processAllUsers(List users, Context context) { - UserManagerCompat userManager = UserManagerCompat.getInstance(context); - HashSet validKeys = new HashSet<>(); - for (UserHandle user : users) { - validKeys.add(USER_FOLDER_ID_PREFIX + userManager.getSerialNumberForUser(user)); - } - - SharedPreferences prefs = prefs(context); - SharedPreferences.Editor editor = prefs.edit(); - for (String key : prefs.getAll().keySet()) { - if (!validKeys.contains(key)) { - editor.remove(key); - } - } - editor.apply(); - } - - /** - * For each user, if a work folder has not been created, mark it such that the folder will - * never get created. - */ - public static void markExistingUsersForNoFolderCreation(Context context) { - UserManagerCompat userManager = UserManagerCompat.getInstance(context); - UserHandle myUser = Process.myUserHandle(); - - SharedPreferences prefs = null; - for (UserHandle user : userManager.getUserProfiles()) { - if (myUser.equals(user)) { - continue; - } - if (prefs == null) { - prefs = prefs(context); - } - String folderIdKey = USER_FOLDER_ID_PREFIX + userManager.getSerialNumberForUser(user); - if (!prefs.contains(folderIdKey)) { - prefs.edit().putLong(folderIdKey, ItemInfo.NO_ID).apply(); - } - } - } - - public static SharedPreferences prefs(Context context) { - return context.getSharedPreferences( - LauncherFiles.MANAGED_USER_PREFERENCES_KEY, Context.MODE_PRIVATE); - } -} diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index 1be33d2f86..9e551272d6 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -15,6 +15,9 @@ */ package com.android.launcher3.ui; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + import android.app.Instrumentation; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -34,7 +37,6 @@ import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject2; import android.support.test.uiautomator.Until; import android.view.MotionEvent; - import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.LauncherSettings; @@ -46,17 +48,11 @@ import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.testcomponent.AppWidgetNoConfig; import com.android.launcher3.testcomponent.AppWidgetWithConfig; -import com.android.launcher3.util.ManagedProfileHeuristic; - -import org.junit.Before; - import java.util.Locale; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import org.junit.Before; /** * Base class for all instrumentation tests providing various utility methods. @@ -221,7 +217,6 @@ public abstract class AbstractLauncherUiTest { mMainThreadExecutor.execute(new Runnable() { @Override public void run() { - ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mTargetContext); LauncherAppState.getInstance(mTargetContext).getModel().forceReload(); } }); From d82c5cd2b05b2260c6c600fe31cd4680e2307121 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Tue, 27 Feb 2018 10:10:29 -0800 Subject: [PATCH 003/127] Set disabled state when getting new icon from DrawableFactory. Change-Id: Ic9c508d24cc0e65d45f5c1f4bcbe8d5cd7fb9200 --- .../android/launcher3/LauncherAppTransitionManagerImpl.java | 6 ++---- src/com/android/launcher3/BubbleTextView.java | 1 - src/com/android/launcher3/graphics/DrawableFactory.java | 4 +++- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index 0fe29e35dc..3ba06620b1 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -501,10 +501,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag mFloatingView = new View(mLauncher); if (isBubbleTextView && v.getTag() instanceof ItemInfoWithIcon ) { // Create a copy of the app icon - ItemInfoWithIcon info = (ItemInfoWithIcon) v.getTag(); - FastBitmapDrawable d = DrawableFactory.get(mLauncher).newIcon(info); - d.setIsDisabled(info.isDisabled()); - mFloatingView.setBackground(d); + mFloatingView.setBackground( + DrawableFactory.get(mLauncher).newIcon((ItemInfoWithIcon) v.getTag())); } // Position the floating view exactly on top of the original diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index dbdb2dca95..4f50d1a427 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -231,7 +231,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, FastBitmapDrawable iconDrawable = DrawableFactory.get(getContext()).newIcon(info); mBadgeColor = IconPalette.getMutedColor(info.iconColor, 0.54f); - iconDrawable.setIsDisabled(info.isDisabled()); setIcon(iconDrawable); setText(info.title); if (info.contentDescription != null) { diff --git a/src/com/android/launcher3/graphics/DrawableFactory.java b/src/com/android/launcher3/graphics/DrawableFactory.java index 32d9e41455..3393469223 100644 --- a/src/com/android/launcher3/graphics/DrawableFactory.java +++ b/src/com/android/launcher3/graphics/DrawableFactory.java @@ -65,7 +65,9 @@ public class DrawableFactory { * Returns a FastBitmapDrawable with the icon. */ public FastBitmapDrawable newIcon(ItemInfoWithIcon info) { - return new FastBitmapDrawable(info); + FastBitmapDrawable drawable = new FastBitmapDrawable(info); + drawable.setIsDisabled(info.isDisabled()); + return drawable; } /** From 30d075727835eea60d5c4f50963f4c04f8c48b56 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Tue, 27 Feb 2018 11:30:44 -0800 Subject: [PATCH 004/127] Default swiping to N-1 task from home to true Bug: 73854835 Change-Id: I585dc2f95e0abbffe45ef28b14268350aba5b9a9 --- .../launcher3/uioverrides/RecentsViewStateController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java index 7d371e96bf..80ecb924e5 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java @@ -75,7 +75,7 @@ public class RecentsViewStateController implements StateHandler { public void setStateWithAnimation(final LauncherState toState, AnimatorSetBuilder builder, AnimationConfig config) { boolean settingEnabled = Utilities.getPrefs(mLauncher) - .getBoolean("pref_scroll_to_first_task", false); + .getBoolean("pref_scroll_to_first_task_default_true", true); mIsRecentsScrollingToFirstTask = mLauncher.isInState(NORMAL) && toState == OVERVIEW && settingEnabled; // TODO: Instead of animating the workspace translationX, move the contents From 2bba1900e0880a2fdd7ee5963e2763c7ba8ca701 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 27 Feb 2018 12:20:50 -0800 Subject: [PATCH 005/127] Adding temporary logs to capture configuration changes and item deletions Bug: 72481685 Bug: 73814840 Change-Id: I1e30632647ad08a08d84c49875bc7b6cac3be1fb --- src/com/android/launcher3/Launcher.java | 19 +++++--- .../android/launcher3/LauncherProvider.java | 6 +++ .../android/launcher3/model/ModelWriter.java | 46 ++++++++++++------- 3 files changed, 48 insertions(+), 23 deletions(-) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 55bfef6cb0..7209d9dca9 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -408,6 +408,11 @@ public class Launcher extends BaseActivity if ((diff & (CONFIG_ORIENTATION | CONFIG_SCREEN_SIZE)) != 0) { mUserEventDispatcher = null; initDeviceProfile(mDeviceProfile.inv); + FileLog.d(TAG, "Config changed, my orientation=" + + getResources().getConfiguration().orientation + + ", new orientation=" + newConfig.orientation + + ", old orientation=" + mOldConfig.orientation + + ", isTransposed=" + mDeviceProfile.isVerticalBarLayout()); dispatchDeviceProfileChanged(); getRootView().dispatchInsets(); @@ -2752,18 +2757,20 @@ public class Launcher extends BaseActivity writer.println(prefix + " " + tag.toString()); } } - - try { - FileLog.flushAll(writer); - } catch (Exception e) { - // Ignore - } } writer.println(prefix + "Misc:"); writer.print(prefix + "\tmWorkspaceLoading=" + mWorkspaceLoading); writer.print(" mPendingRequestArgs=" + mPendingRequestArgs); writer.println(" mPendingActivityResult=" + mPendingActivityResult); + writer.println(" deviceProfile isTransposed=" + getDeviceProfile().isVerticalBarLayout()); + writer.println(" orientation=" + getResources().getConfiguration().orientation); + + try { + FileLog.flushAll(writer); + } catch (Exception e) { + // Ignore + } mModel.dumpState(prefix, fd, writer, args); diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java index 138ea0f650..053dc356eb 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -56,6 +56,7 @@ import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.DbDowngradeHelper; +import com.android.launcher3.model.ModelWriter; import com.android.launcher3.provider.LauncherDbUtils; import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction; import com.android.launcher3.provider.RestoreDbTask; @@ -320,6 +321,11 @@ public class LauncherProvider extends ContentProvider { @Override public int delete(Uri uri, String selection, String[] selectionArgs) { + if (ModelWriter.DEBUG_DELETE) { + String args = selectionArgs == null ? null : TextUtils.join(",", selectionArgs); + FileLog.d(TAG, "Delete uri=" + uri + ", selection=" + selection + + ", selectionArgs=" + args, new Exception()); + } createDbIfNotExists(); SqlArguments args = new SqlArguments(uri, selection, selectionArgs); diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java index 032ed780d6..40e0f49a86 100644 --- a/src/com/android/launcher3/model/ModelWriter.java +++ b/src/com/android/launcher3/model/ModelWriter.java @@ -32,6 +32,7 @@ import com.android.launcher3.LauncherSettings; import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.LauncherSettings.Settings; import com.android.launcher3.ShortcutInfo; +import com.android.launcher3.logging.FileLog; import com.android.launcher3.util.ContentWriter; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.LooperExecutor; @@ -46,6 +47,7 @@ import java.util.concurrent.Executor; public class ModelWriter { private static final String TAG = "ModelWriter"; + public static final boolean DEBUG_DELETE = true; private final Context mContext; private final BgDataModel mBgDataModel; @@ -243,14 +245,21 @@ public class ModelWriter { * Removes the specified items from the database */ public void deleteItemsFromDatabase(final Iterable items) { - mWorkerExecutor.execute(new Runnable() { - public void run() { - for (ItemInfo item : items) { - final Uri uri = Favorites.getContentUri(item.id); - mContext.getContentResolver().delete(uri, null, null); + if (DEBUG_DELETE) { + // Log it on the colling thread to get the proper stack trace + FileLog.d(TAG, "Starting item deletion", new Exception()); + for (ItemInfo item : items) { + FileLog.d(TAG, "deleting item " + item); + } + FileLog.d(TAG, "Finished deleting items"); + } - mBgDataModel.removeItem(mContext, item); - } + mWorkerExecutor.execute(() -> { + for (ItemInfo item : items) { + final Uri uri = Favorites.getContentUri(item.id); + mContext.getContentResolver().delete(uri, null, null); + + mBgDataModel.removeItem(mContext, item); } }); } @@ -259,17 +268,20 @@ public class ModelWriter { * Remove the specified folder and all its contents from the database. */ public void deleteFolderAndContentsFromDatabase(final FolderInfo info) { - mWorkerExecutor.execute(new Runnable() { - public void run() { - ContentResolver cr = mContext.getContentResolver(); - cr.delete(LauncherSettings.Favorites.CONTENT_URI, - LauncherSettings.Favorites.CONTAINER + "=" + info.id, null); - mBgDataModel.removeItem(mContext, info.contents); - info.contents.clear(); + if (DEBUG_DELETE) { + // Log it on the colling thread to get the proper stack trace + FileLog.d(TAG, "Deleting folder " + info, new Exception()); + } - cr.delete(LauncherSettings.Favorites.getContentUri(info.id), null, null); - mBgDataModel.removeItem(mContext, info); - } + mWorkerExecutor.execute(() -> { + ContentResolver cr = mContext.getContentResolver(); + cr.delete(LauncherSettings.Favorites.CONTENT_URI, + LauncherSettings.Favorites.CONTAINER + "=" + info.id, null); + mBgDataModel.removeItem(mContext, info.contents); + info.contents.clear(); + + cr.delete(LauncherSettings.Favorites.getContentUri(info.id), null, null); + mBgDataModel.removeItem(mContext, info); }); } From 270d6567cc920cf3c5ceba3bee22fc2ee2b95f63 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Tue, 27 Feb 2018 13:55:35 -0800 Subject: [PATCH 006/127] Don't animate the workspace background alpha during recents anim This is somewhat expensive and could cause jank Change-Id: I75c2e957781c865e8d275ecc083e5edfa31e04d3 --- .../android/launcher3/LauncherAppTransitionManagerImpl.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index 8f498d27fe..68f6667d88 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -16,7 +16,6 @@ package com.android.launcher3; -import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA; import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS; import static com.android.systemui.shared.recents.utilities.Utilities.getNextFrameNumber; import static com.android.systemui.shared.recents.utilities.Utilities.getSurface; @@ -323,9 +322,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag launcherAnimator.play(recenterWorkspace); CellLayout currentWorkspacePage = (CellLayout) workspace.getPageAt( workspace.getCurrentPage()); - Animator hideWorkspaceScrim = ObjectAnimator.ofInt( - currentWorkspacePage.getScrimBackground(), DRAWABLE_ALPHA, 0); - launcherAnimator.play(hideWorkspaceScrim); launcherAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR); launcherAnimator.setDuration(RECENTS_LAUNCH_DURATION); From efa671294e8ac67a0554ff5679255ee8c9bf747d Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 21 Feb 2018 16:19:26 -0800 Subject: [PATCH 007/127] Fix some issues with split screen animation - Notify WM when the next draw after split screen happens - Close the menu once we invoke split screen Bug: 73118672 Change-Id: I9a42635f1f5c29e347bdec3034f6aa8be332c8d2 --- quickstep/libs/sysui_shared.jar | Bin 116472 -> 116722 bytes .../android/quickstep/TaskSystemShortcut.java | 71 ++++++++++++++---- 2 files changed, 58 insertions(+), 13 deletions(-) diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar index d5859a7a5466d3b518986c68b04f8103b20f14c1..0e45791a6042a11cf705d873a7209e7d64747457 100644 GIT binary patch delta 13962 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 LZYa`#9wPlesZe{t delta 13912 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 GDE|j0tuAx` diff --git a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java index 75d8619eae..e172291daa 100644 --- a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java +++ b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java @@ -19,13 +19,18 @@ package com.android.quickstep; import android.app.ActivityOptions; import android.content.ComponentName; import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.Rect; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; import android.view.View; +import android.view.ViewTreeObserver.OnPreDrawListener; +import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; import com.android.launcher3.R; @@ -34,9 +39,15 @@ import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.util.InstantAppResolver; import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat; +import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture; +import com.android.systemui.shared.recents.view.RecentsTransition; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.ActivityOptionsCompat; +import com.android.systemui.shared.system.WindowManagerWrapper; +import java.util.Collections; +import java.util.List; import java.util.function.Consumer; /** @@ -86,9 +97,10 @@ public class TaskSystemShortcut extends SystemShortcut } } - public static class SplitScreen extends TaskSystemShortcut { + public static class SplitScreen extends TaskSystemShortcut implements OnPreDrawListener { private Handler mHandler; + private TaskView mTaskView; public SplitScreen() { super(R.drawable.ic_split_screen, R.string.recent_task_option_split_screen); @@ -104,22 +116,55 @@ public class TaskSystemShortcut extends SystemShortcut if (!task.isDockable) { return null; } + mTaskView = taskView; return (v -> { - final ActivityOptions options = ActivityOptionsCompat.makeSplitScreenOptions(true); - final Consumer resultCallback = success -> { - if (success) { - launcher.getOverviewPanel().removeView(taskView); - } - }; - ActivityManagerWrapper.getInstance().startActivityFromRecentsAsync( - task.key, options, resultCallback, mHandler); + AbstractFloatingView.closeOpenViews(launcher, true, + AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE); - // TODO improve transition; see: - // DockedFirstAnimationFrameEvent - // RecentsTransitionHelper#composeDockAnimationSpec - // WindowManagerWrapper#overridePendingAppTransitionMultiThumbFuture + if (ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key.id, + ActivityOptionsCompat.makeSplitScreenOptions(true))) { + ISystemUiProxy sysUiProxy = RecentsModel.getInstance(launcher).getSystemUiProxy(); + try { + sysUiProxy.onSplitScreenInvoked(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to notify SysUI of split screen: ", e); + return; + } + + final Runnable animStartedListener = () -> { + mTaskView.getViewTreeObserver().addOnPreDrawListener(SplitScreen.this); + launcher.getOverviewPanel().removeView(taskView); + }; + + final int[] position = new int[2]; + taskView.getLocationOnScreen(position); + final int width = (int) (taskView.getWidth() * taskView.getScaleX()); + final int height = (int) (taskView.getHeight() * taskView.getScaleY()); + final Rect taskBounds = new Rect(position[0], position[1], + position[0] + width, position[1] + height); + + Bitmap thumbnail = RecentsTransition.drawViewIntoHardwareBitmap( + taskBounds.width(), taskBounds.height(), taskView, 1f, Color.BLACK); + AppTransitionAnimationSpecsFuture future = + new AppTransitionAnimationSpecsFuture(mHandler) { + @Override + public List composeSpecs() { + return Collections.singletonList(new AppTransitionAnimationSpecCompat( + task.key.id, thumbnail, taskBounds)); + } + }; + WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture( + future, animStartedListener, mHandler, true /* scaleUp */); + } }); } + + @Override + public boolean onPreDraw() { + mTaskView.getViewTreeObserver().removeOnPreDrawListener(this); + WindowManagerWrapper.getInstance().endProlongedAnimations(); + return true; + } } public static class Pin extends TaskSystemShortcut { From c11fac355d5057ad066adc3abbbb2b2d64fba5e7 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 27 Feb 2018 19:20:15 -0800 Subject: [PATCH 008/127] Fixing widgets get deteled because of double bind If the AppWidgetHost starts listening in the middle of bind, it rebinds the old widgets before a new widget is bound, leading to double bind. We should clear all pending binds, before starting a rebind. As an extra check only rebind a view which is attached to the screen. Bug: 73814840 Change-Id: Ie3af683dc4095b158547e700d11e4faf7999466f --- src/com/android/launcher3/Launcher.java | 1 + src/com/android/launcher3/LauncherAppWidgetHost.java | 2 +- .../launcher3/widget/LauncherAppWidgetHostView.java | 7 ++++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 7209d9dca9..5ac53a88c1 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -2239,6 +2239,7 @@ public class Launcher extends BaseActivity // Clear the workspace because it's going to be rebound mWorkspace.clearDropTargets(); mWorkspace.removeAllWorkspaceScreens(); + mAppWidgetHost.clearViews(); if (mHotseat != null) { mHotseat.resetLayout(); diff --git a/src/com/android/launcher3/LauncherAppWidgetHost.java b/src/com/android/launcher3/LauncherAppWidgetHost.java index 7bc713922b..56671a1582 100644 --- a/src/com/android/launcher3/LauncherAppWidgetHost.java +++ b/src/com/android/launcher3/LauncherAppWidgetHost.java @@ -236,7 +236,7 @@ public class LauncherAppWidgetHost extends AppWidgetHost { } @Override - protected void clearViews() { + public void clearViews() { super.clearViews(); mViews.clear(); } diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java index 0b1474a037..9d74218e04 100644 --- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java @@ -488,13 +488,14 @@ public class LauncherAppWidgetHostView extends AppWidgetHostView // Only reinflate when the final configuration is same as the required configuration if (mReinflateOnConfigChange && isSameOrientation()) { mReinflateOnConfigChange = false; - if (isAttachedToWindow()) { - reInflate(); - } + reInflate(); } } public void reInflate() { + if (!isAttachedToWindow()) { + return; + } LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag(); // Remove and rebind the current widget (which was inflated in the wrong // orientation), but don't delete it from the database From 93e9dbddc554bcb851c6ff6c838a199239249fa1 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Tue, 27 Feb 2018 15:24:35 -0800 Subject: [PATCH 009/127] Fix app opening transition for deep shortcuts. With this change, the floating view now starts on top of the deep shortcut icon; before this change the view stared in the middle of the text portion of the view. Bug: 70220260 Change-Id: I7a1ed705f6f8d9d2ff594f52c4cf678aa0575012 --- .../LauncherAppTransitionManagerImpl.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index b614d15107..1df8cfd285 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -51,6 +51,8 @@ import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.graphics.DrawableFactory; +import com.android.launcher3.shortcuts.DeepShortcutTextView; +import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.quickstep.RecentsAnimationInterpolator; import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds; import com.android.quickstep.RecentsView; @@ -498,7 +500,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag * @return Animator that controls the icon used to launch the target. */ private AnimatorSet getIconAnimator(View v) { - boolean isBubbleTextView = v instanceof BubbleTextView; + final boolean isBubbleTextView = v instanceof BubbleTextView; mFloatingView = new View(mLauncher); if (isBubbleTextView && v.getTag() instanceof ItemInfoWithIcon ) { // Create a copy of the app icon @@ -510,14 +512,24 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag // Position the floating view exactly on top of the original Rect rect = new Rect(); - mDragLayer.getDescendantRectRelativeToSelf(v, rect); - int viewLocationStart = mIsRtl + final boolean isDeepShortcutTextView = v instanceof DeepShortcutTextView + && v.getParent() != null && v.getParent() instanceof DeepShortcutView; + if (isDeepShortcutTextView) { + // Deep shortcut views have their icon drawn in a sibling view. + DeepShortcutView view = (DeepShortcutView) v.getParent(); + mDragLayer.getDescendantRectRelativeToSelf(view.getIconView(), rect); + } else { + mDragLayer.getDescendantRectRelativeToSelf(v, rect); + } + final int viewLocationStart = mIsRtl ? mDeviceProfile.widthPx - rect.right : rect.left; - int viewLocationTop = rect.top; + final int viewLocationTop = rect.top; - if (isBubbleTextView) { + if (isBubbleTextView && !isDeepShortcutTextView) { ((BubbleTextView) v).getIconBounds(rect); + } else { + rect.set(0, 0, rect.width(), rect.height()); } LayoutParams lp = new LayoutParams(rect.width(), rect.height()); lp.ignoreInsets = true; From d6aa658b6f60bbea0e4ebbb0ce7d114bfd3240dd Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Wed, 28 Feb 2018 08:19:30 -0800 Subject: [PATCH 010/127] Reduce launcher resume animation start delay from 150 to 100. Bug: 70220260 Change-Id: I61c76a619841fc91d080b53190fd46aa20667e30 --- .../com/android/launcher3/LauncherAppTransitionManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index fea83d6309..5259e04a2a 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -80,7 +80,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag "android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"; private static final int RECENTS_LAUNCH_DURATION = 336; - private static final int LAUNCHER_RESUME_START_DELAY = 150; + private static final int LAUNCHER_RESUME_START_DELAY = 100; private static final int CLOSING_TRANSITION_DURATION_MS = 350; // Progress = 0: All apps is fully pulled up, Progress = 1: All apps is fully pulled down. From cfc519d0a86507653a1734f6f64d9edc091b9d80 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 23 Feb 2018 10:27:57 -0800 Subject: [PATCH 011/127] Only load thumbnails for visible tasks. Bug: 73651529 Change-Id: Id45c5381c43b8c26447be5492c51af83cffe32a9 --- .../com/android/quickstep/RecentsView.java | 68 +++++++++++++++++-- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java index 9e07b4977f..991852ae7b 100644 --- a/quickstep/src/com/android/quickstep/RecentsView.java +++ b/quickstep/src/com/android/quickstep/RecentsView.java @@ -22,6 +22,7 @@ import static com.android.quickstep.TaskView.CURVE_FACTOR; import static com.android.quickstep.TaskView.CURVE_INTERPOLATOR; import android.animation.LayoutTransition; +import android.animation.LayoutTransition.TransitionListener; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; @@ -38,8 +39,10 @@ import android.graphics.Shader.TileMode; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.util.AttributeSet; +import android.util.SparseBooleanArray; import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; import android.widget.FrameLayout; import com.android.launcher3.DeviceProfile; @@ -114,6 +117,7 @@ public class RecentsView extends PagedView implements Insettable, OnSharedPrefer private boolean mScrimOnLeft; private boolean mFirstTaskIconScaledDown = false; + private SparseBooleanArray mPrevVisibleTasks = new SparseBooleanArray(); public RecentsView(Context context) { this(context, null); @@ -167,12 +171,28 @@ public class RecentsView extends PagedView implements Insettable, OnSharedPrefer private void setupLayoutTransition() { // We want to show layout transitions when pages are deleted, to close the gap. + // TODO: We should this manually so we can control the animation (fill in the gap as the + // dismissing task is being tracked, and also so we can update the visible task data during + // the transition. For now, the workaround is to expand the visible tasks to load. mLayoutTransition = new LayoutTransition(); mLayoutTransition.enableTransitionType(LayoutTransition.DISAPPEARING); mLayoutTransition.enableTransitionType(LayoutTransition.CHANGE_DISAPPEARING); mLayoutTransition.disableTransitionType(LayoutTransition.APPEARING); mLayoutTransition.disableTransitionType(LayoutTransition.CHANGE_APPEARING); + mLayoutTransition.addTransitionListener(new TransitionListener() { + @Override + public void startTransition(LayoutTransition layoutTransition, ViewGroup viewGroup, + View view, int i) { + loadVisibleTaskData(); + } + + @Override + public void endTransition(LayoutTransition layoutTransition, ViewGroup viewGroup, + View view, int i) { + loadVisibleTaskData(); + } + }); setLayoutTransition(mLayoutTransition); } @@ -314,13 +334,16 @@ public class RecentsView extends PagedView implements Insettable, OnSharedPrefer // Rebind and reset all task views for (int i = tasks.size() - 1; i >= 0; i--) { + final int pageIndex = tasks.size() - i - 1 + mFirstTaskIndex; final Task task = tasks.get(i); - final TaskView taskView = (TaskView) getChildAt(tasks.size() - i - 1 + mFirstTaskIndex); + final TaskView taskView = (TaskView) getChildAt(pageIndex); taskView.bind(task); taskView.resetVisualProperties(); - loader.loadTaskData(task); } updateCurveProperties(); + // Reload the set of visible task's data + mPrevVisibleTasks.clear(); + loadVisibleTaskData(); applyIconScale(false /* animate */); if (oldChildCount != getChildCount()) { @@ -414,9 +437,14 @@ public class RecentsView extends PagedView implements Insettable, OnSharedPrefer } @Override - public void computeScroll() { - super.computeScroll(); + protected boolean computeScrollHelper() { + boolean scrolling = super.computeScrollHelper(); updateCurveProperties(); + if (scrolling || (mTouchState == TOUCH_STATE_SCROLLING)) { + // After scrolling, update the visible task's data + loadVisibleTaskData(); + } + return scrolling; } /** @@ -444,6 +472,32 @@ public class RecentsView extends PagedView implements Insettable, OnSharedPrefer } } + /** + * Iterates through all thet asks, and loads the associated task data for newly visible tasks, + * and unloads the associated task data for tasks that are no longer visible. + */ + private void loadVisibleTaskData() { + RecentsTaskLoader loader = mModel.getRecentsTaskLoader(); + int centerPageIndex = getPageNearestToCenterOfScreen(); + int lower = Math.max(mFirstTaskIndex, centerPageIndex - 2); + int upper = Math.min(centerPageIndex + 2, getChildCount() - 1); + for (int i = mFirstTaskIndex; i < getChildCount(); i++) { + TaskView taskView = (TaskView) getChildAt(i); + Task task = taskView.getTask(); + boolean visible = lower <= i && i <= upper; + if (visible) { + if (!mPrevVisibleTasks.get(i)) { + loader.loadTaskData(task); + } + } else { + if (mPrevVisibleTasks.get(i)) { + loader.unloadTaskData(task); + } + } + mPrevVisibleTasks.put(i, visible); + } + } + public void onTaskDismissed(TaskView taskView) { ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id); removeView(taskView); @@ -493,14 +547,16 @@ public class RecentsView extends PagedView implements Insettable, OnSharedPrefer addView(taskView, mFirstTaskIndex); setLayoutTransition(mLayoutTransition); } + mRunningTaskId = runningTaskId; + setCurrentPage(mFirstTaskIndex); if (!needsReload) { needsReload = !mModel.isLoadPlanValid(mLoadPlanId); } if (needsReload) { mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan); + } else { + loadVisibleTaskData(); } - mRunningTaskId = runningTaskId; - setCurrentPage(mFirstTaskIndex); if (mCurrentPage >= mFirstTaskIndex) { getPageAt(mCurrentPage).setAlpha(0); } From 62a70be27ac9313b163d25562407f635bef5a45a Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 23 Feb 2018 15:10:05 -0800 Subject: [PATCH 012/127] Enable trim memory callbacks to the loader, background task preloading - Also enable the high-res thumbnail loader Bug: 73651529 Change-Id: Ic23997f10289ea10cb1f41104e07029c9102c Signed-off-by: Winson Chung --- quickstep/res/values/dimens.xml | 3 ++ .../launcher3/uioverrides/UiFactory.java | 15 ++++++ .../com/android/quickstep/RecentsModel.java | 50 +++++++++++++++++-- .../com/android/quickstep/RecentsView.java | 21 +++++++- src/com/android/launcher3/Launcher.java | 2 + src/com/android/launcher3/PagedView.java | 1 - .../launcher3/uioverrides/UiFactory.java | 4 ++ 7 files changed, 91 insertions(+), 5 deletions(-) diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index 0956048429..9b6c0535c7 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -25,6 +25,9 @@ 20dp 10dp + + 600dp 500dp 250dp diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java index 7bd43668ec..71cdd10989 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java @@ -29,6 +29,7 @@ import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.graphics.BitmapRenderer; import com.android.launcher3.util.TouchController; import com.android.quickstep.OverviewInteractionState; +import com.android.quickstep.RecentsModel; import com.android.quickstep.RecentsView; import com.android.systemui.shared.recents.view.RecentsTransition; @@ -88,4 +89,18 @@ public class UiFactory { RecentsView recents = launcher.getOverviewPanel(); recents.reset(); } + + public static void onStart(Launcher launcher) { + RecentsModel model = RecentsModel.getInstance(launcher); + if (model != null) { + model.onStart(); + } + } + + public static void onTrimMemory(Launcher launcher, int level) { + RecentsModel model = RecentsModel.getInstance(launcher); + if (model != null) { + model.onTrimMemory(level); + } + } } diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java index 7fe77510df..90e857ce0e 100644 --- a/quickstep/src/com/android/quickstep/RecentsModel.java +++ b/quickstep/src/com/android/quickstep/RecentsModel.java @@ -16,6 +16,8 @@ package com.android.quickstep; import android.annotation.TargetApi; +import android.app.ActivityManager; +import android.content.ComponentCallbacks2; import android.content.ComponentName; import android.content.Context; import android.content.pm.ActivityInfo; @@ -29,6 +31,7 @@ import android.support.annotation.WorkerThread; import android.util.LruCache; import android.util.SparseArray; +import com.android.launcher3.Launcher; import com.android.launcher3.MainThreadExecutor; import com.android.launcher3.R; import com.android.launcher3.util.Preconditions; @@ -51,7 +54,6 @@ import java.util.function.Consumer; */ @TargetApi(Build.VERSION_CODES.O) public class RecentsModel extends TaskStackChangeListener { - // We do not need any synchronization for this variable as its only written on UI thread. private static RecentsModel INSTANCE; @@ -83,10 +85,16 @@ public class RecentsModel extends TaskStackChangeListener { private int mTaskChangeId; private ISystemUiProxy mSystemUiProxy; private boolean mClearAssistCacheOnStackChange = true; + private final boolean mPreloadTasksInBackground; private RecentsModel(Context context) { mContext = context; + ActivityManager activityManager = + (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + mPreloadTasksInBackground = !activityManager.isLowRamDevice(); + mMainThreadExecutor = new MainThreadExecutor(); + Resources res = context.getResources(); mRecentsTaskLoader = new RecentsTaskLoader(mContext, res.getInteger(R.integer.config_recentsMaxThumbnailCacheSize), @@ -100,8 +108,6 @@ public class RecentsModel extends TaskStackChangeListener { } }; mRecentsTaskLoader.startLoader(mContext); - - mMainThreadExecutor = new MainThreadExecutor(); ActivityManagerWrapper.getInstance().registerTaskStackListener(this); mTaskChangeId = 1; @@ -162,6 +168,31 @@ public class RecentsModel extends TaskStackChangeListener { } } + @Override + public void onTaskStackChangedBackground() { + int userId = UserHandle.myUserId(); + if (!mPreloadTasksInBackground || !checkCurrentUserId(userId, false /* debug */)) { + // TODO: Only register this for the current user + return; + } + + // Preload a fixed number of task icons/thumbnails in the background + ActivityManager.RunningTaskInfo runningTaskInfo = + ActivityManagerWrapper.getInstance().getRunningTask(); + RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext); + RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options(); + launchOpts.runningTaskId = runningTaskInfo != null ? runningTaskInfo.id : -1; + launchOpts.numVisibleTasks = 2; + launchOpts.numVisibleTaskThumbnails = 2; + launchOpts.onlyLoadForCache = true; + launchOpts.onlyLoadPausedActivities = true; + launchOpts.loadThumbnails = true; + PreloadOptions preloadOpts = new PreloadOptions(); + preloadOpts.loadTitles = false; + plan.preloadPlan(preloadOpts, mRecentsTaskLoader, -1, userId); + mRecentsTaskLoader.loadTasks(plan, launchOpts); + } + public boolean isLoadPlanValid(int resultId) { return mTaskChangeId == resultId; } @@ -178,6 +209,19 @@ public class RecentsModel extends TaskStackChangeListener { return mSystemUiProxy; } + public void onStart() { + mRecentsTaskLoader.startLoader(mContext); + mRecentsTaskLoader.getHighResThumbnailLoader().setVisible(true); + } + + public void onTrimMemory(int level) { + if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { + // We already stop the loader in UI_HIDDEN, so stop the high res loader as well + mRecentsTaskLoader.getHighResThumbnailLoader().setVisible(false); + } + mRecentsTaskLoader.onTrimMemory(level); + } + @WorkerThread public void preloadAssistData(int taskId, Bundle data) { mMainThreadExecutor.execute(() -> { diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java index 991852ae7b..42677c170b 100644 --- a/quickstep/src/com/android/quickstep/RecentsView.java +++ b/quickstep/src/com/android/quickstep/RecentsView.java @@ -26,6 +26,7 @@ import android.animation.LayoutTransition.TransitionListener; import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; @@ -85,6 +86,8 @@ public class RecentsView extends PagedView implements Insettable, OnSharedPrefer private LayoutTransition mLayoutTransition; private Runnable mNextPageSwitchRunnable; + private float mFastFlingVelocity; + /** * TODO: Call reloadIdNeeded in onTaskStackChanged. */ @@ -199,7 +202,9 @@ public class RecentsView extends PagedView implements Insettable, OnSharedPrefer @Override protected void onFinishInflate() { super.onFinishInflate(); + Resources res = getResources(); mFirstTaskIndex = getPageCount(); + mFastFlingVelocity = res.getDimensionPixelSize(R.dimen.recents_fast_fling_velocity); } @Override @@ -327,8 +332,10 @@ public class RecentsView extends PagedView implements Insettable, OnSharedPrefer } while (getChildCount() > requiredChildCount) { final TaskView taskView = (TaskView) getChildAt(getChildCount() - 1); + final Task task = taskView.getTask(); removeView(taskView); - loader.unloadTaskData(taskView.getTask()); + loader.unloadTaskData(task); + loader.getHighResThumbnailLoader().onTaskInvisible(task); } setLayoutTransition(mLayoutTransition); @@ -439,11 +446,21 @@ public class RecentsView extends PagedView implements Insettable, OnSharedPrefer @Override protected boolean computeScrollHelper() { boolean scrolling = super.computeScrollHelper(); + boolean isFlingingFast = false; updateCurveProperties(); if (scrolling || (mTouchState == TOUCH_STATE_SCROLLING)) { + if (scrolling) { + // Check if we are flinging quickly to disable high res thumbnail loading + isFlingingFast = mScroller.getCurrVelocity() > mFastFlingVelocity; + } + // After scrolling, update the visible task's data loadVisibleTaskData(); } + + // Update the high res thumbnail loader + RecentsTaskLoader loader = mModel.getRecentsTaskLoader(); + loader.getHighResThumbnailLoader().setFlingingFast(isFlingingFast); return scrolling; } @@ -488,10 +505,12 @@ public class RecentsView extends PagedView implements Insettable, OnSharedPrefer if (visible) { if (!mPrevVisibleTasks.get(i)) { loader.loadTaskData(task); + loader.getHighResThumbnailLoader().onTaskVisible(task); } } else { if (mPrevVisibleTasks.get(i)) { loader.unloadTaskData(task); + loader.getHighResThumbnailLoader().onTaskInvisible(task); } } mPrevVisibleTasks.put(i, visible); diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 5ac53a88c1..38b0140781 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -829,6 +829,7 @@ public class Launcher extends BaseActivity mScrimAnimator.start(); } mShouldFadeInScrim = false; + UiFactory.onStart(this); } @Override @@ -2171,6 +2172,7 @@ public class Launcher extends BaseActivity if (mLauncherCallbacks != null) { mLauncherCallbacks.onTrimMemory(level); } + UiFactory.onTrimMemory(this, level); } @Override diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index ca8039ce9c..6ec209a41d 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -552,7 +552,6 @@ public abstract class PagedView extends ViewGrou // Notify the user when the page changes announceForAccessibility(getCurrentPageDescription()); } - return true; } return false; } diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java index 64a29ea3e7..a16ae488fe 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java @@ -64,4 +64,8 @@ public class UiFactory { public static void resetOverview(Launcher launcher) { } public static void onLauncherStateOrFocusChanged(Launcher launcher) { } + + public static void onStart(Launcher launcher) { } + + public static void onTrimMemory(Launcher launcher, int level) { } } From dd2424296a5639cdd707ebc2a7a830471aa4c3dd Mon Sep 17 00:00:00 2001 From: Mario Bertschler Date: Wed, 28 Feb 2018 14:16:38 -0800 Subject: [PATCH 013/127] Fix for floatingheader snap value being higher than the max translation if flinging quickly the all-apps recycler view. Bug: 73151273 Change-Id: If7acbf7b48f69ea6a818a83d519049496b86ced3 --- src/com/android/launcher3/allapps/FloatingHeaderView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java index d8a9f63647..416469f890 100644 --- a/src/com/android/launcher3/allapps/FloatingHeaderView.java +++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java @@ -131,7 +131,7 @@ public class FloatingHeaderView extends LinearLayout implements mSnappedScrolledY = currentScrollY - mMaxTranslation; } else if (mTranslationY <= -mMaxTranslation) { // hide or stay hidden mHeaderCollapsed = true; - mSnappedScrolledY = currentScrollY; + mSnappedScrolledY = -mMaxTranslation; } } } From 2e2e2b4a6397ba2eb0f781e134ce533facc5e6fa Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 27 Feb 2018 16:52:55 -0800 Subject: [PATCH 014/127] Fixing widget label not being rendered in multi-window mode Bug: 73709754 Change-Id: Id6342e3412c2b247e052bc45c01a484422a7c011 --- src/com/android/launcher3/DeviceProfile.java | 8 ++++++++ .../launcher3/widget/DeferredAppWidgetHostView.java | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index ba55b36a8b..ea52324a5f 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -249,6 +249,14 @@ public class DeviceProfile { return profile; } + /** + * Inverse of {@link #getMultiWindowProfile(Context, Point)} + * @return device profile corresponding to the current orientation in non multi-window mode. + */ + public DeviceProfile getFullScreenProfile() { + return isLandscape ? inv.landscapeProfile : inv.portraitProfile; + } + /** * Adjusts the profile so that the labels on the Workspace are hidden. * It is important to call this method after the All Apps variables have been set. diff --git a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java index 37e5efcb78..3a24c3d21a 100644 --- a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java @@ -44,7 +44,8 @@ public class DeferredAppWidgetHostView extends LauncherAppWidgetHostView { mPaint = new TextPaint(); mPaint.setColor(Color.WHITE); mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX, - mLauncher.getDeviceProfile().iconTextSizePx, getResources().getDisplayMetrics())); + mLauncher.getDeviceProfile().getFullScreenProfile().iconTextSizePx, + getResources().getDisplayMetrics())); setBackgroundResource(R.drawable.bg_deferred_app_widget); } From 4c1abea9cd08ab9c5e591c2e7ae6514be41030f8 Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Wed, 28 Feb 2018 17:56:28 -0800 Subject: [PATCH 015/127] Fixing generation of fake app-to-recents events Due to some changes, Launcher started to generate these events also upon pressing Home. Moving the generation to a right place triggered only upon the app-to-recents transition. Bug: 72967764 Test: atest google/perf/app-transition/app-transition-to-recents Change-Id: I48e9450765474ed103e558b60ff5bf2b7d6b497d --- .../quickstep/OtherActivityTouchConsumer.java | 50 +---------------- .../WindowTransformSwipeHandler.java | 53 ++++++++++++++++++- 2 files changed, 53 insertions(+), 50 deletions(-) diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java index 488cd72b53..73cd503088 100644 --- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java +++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java @@ -37,10 +37,8 @@ import android.graphics.Color; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; -import android.metrics.LogMaker; import android.os.Bundle; import android.os.Looper; -import android.os.SystemClock; import android.util.Log; import android.view.Choreographer; import android.view.Display; @@ -66,40 +64,6 @@ import com.android.systemui.shared.system.WindowManagerWrapper; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -class EventLogTags { - private EventLogTags() { - } // don't instantiate - - /** 524292 sysui_multi_action (content|4) */ - public static final int SYSUI_MULTI_ACTION = 524292; - - public static void writeSysuiMultiAction(Object[] content) { - android.util.EventLog.writeEvent(SYSUI_MULTI_ACTION, content); - } -} - -class MetricsLogger { - private static MetricsLogger sMetricsLogger; - - private static MetricsLogger getLogger() { - if (sMetricsLogger == null) { - sMetricsLogger = new MetricsLogger(); - } - return sMetricsLogger; - } - - protected void saveLog(Object[] rep) { - EventLogTags.writeSysuiMultiAction(rep); - } - - public void write(LogMaker content) { - if (content.getType() == 0/*MetricsEvent.TYPE_UNKNOWN*/) { - content.setType(4/*MetricsEvent.TYPE_ACTION*/); - } - saveLog(content.serialize()); - } -} - /** * Touch consumer for handling events originating from an activity other than Launcher */ @@ -129,8 +93,6 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC private VelocityTracker mVelocityTracker; private MotionEventQueue mEventQueue; - private final MetricsLogger mMetricsLogger = new MetricsLogger(); - public OtherActivityTouchConsumer(Context base, RunningTaskInfo runningTaskInfo, RecentsModel recentsModel, Intent homeIntent, ISystemUiProxy systemUiProxy, MainThreadExecutor mainThreadExecutor, Choreographer backgroundThreadChoreographer, @@ -312,7 +274,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC private void startTouchTrackingForWindowAnimation(long touchTimeMs) { // Create the shared handler final WindowTransformSwipeHandler handler = - new WindowTransformSwipeHandler(mRunningTask, this); + new WindowTransformSwipeHandler(mRunningTask, this, touchTimeMs); // Preload the plan mRecentsModel.loadTasks(mRunningTask.id, null); @@ -350,16 +312,6 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC TraceHelper.endSection("RecentsController", "Finishing no handler"); controller.finish(false /* toHome */); } - - // Mimic ActivityMetricsLogger.logAppTransitionMultiEvents() logging for - // "Recents" activity for app transition tests. - final LogMaker builder = new LogMaker(761/*APP_TRANSITION*/); - builder.setPackageName("com.android.systemui"); - builder.addTaggedData(871/*FIELD_CLASS_NAME*/, - "com.android.systemui.recents.RecentsActivity"); - builder.addTaggedData(319/*APP_TRANSITION_DELAY_MS*/, - SystemClock.uptimeMillis() - touchTimeMs); - mMetricsLogger.write(builder); } public void onAnimationCanceled() { diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index 19942c3950..3198790f27 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -39,9 +39,11 @@ import android.graphics.Matrix.ScaleToFit; import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; +import android.metrics.LogMaker; import android.os.Build; import android.os.Handler; import android.os.Looper; +import android.os.SystemClock; import android.support.annotation.UiThread; import android.support.annotation.WorkerThread; import android.util.Log; @@ -77,6 +79,40 @@ import com.android.systemui.shared.system.WindowManagerWrapper; import java.util.StringJoiner; +class EventLogTags { + private EventLogTags() { + } // don't instantiate + + /** 524292 sysui_multi_action (content|4) */ + public static final int SYSUI_MULTI_ACTION = 524292; + + public static void writeSysuiMultiAction(Object[] content) { + android.util.EventLog.writeEvent(SYSUI_MULTI_ACTION, content); + } +} + +class MetricsLogger { + private static MetricsLogger sMetricsLogger; + + private static MetricsLogger getLogger() { + if (sMetricsLogger == null) { + sMetricsLogger = new MetricsLogger(); + } + return sMetricsLogger; + } + + protected void saveLog(Object[] rep) { + EventLogTags.writeSysuiMultiAction(rep); + } + + public void write(LogMaker content) { + if (content.getType() == 0/*MetricsEvent.TYPE_UNKNOWN*/) { + content.setType(4/*MetricsEvent.TYPE_ACTION*/); + } + saveLog(content.serialize()); + } +} + @TargetApi(Build.VERSION_CODES.O) public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName(); @@ -189,10 +225,14 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { private final RecentsAnimationWrapper mRecentsAnimationWrapper = new RecentsAnimationWrapper(); private Matrix mTmpMatrix = new Matrix(); + private final long mTouchTimeMs; + private long mLauncherFrameDrawnTime; + private final MetricsLogger mMetricsLogger = new MetricsLogger(); - WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context) { + WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs) { mContext = context; mRunningTaskId = runningTaskInfo.id; + mTouchTimeMs = touchTimeMs; mInputConsumer.registerInputConsumer(); initStateCallbacks(); } @@ -416,11 +456,22 @@ public class WindowTransformSwipeHandler extends BaseSwipeInteractionHandler { if (mLauncherDrawnCallback != null) { mLauncherDrawnCallback.run(); } + mLauncherFrameDrawnTime = SystemClock.uptimeMillis(); } private void initializeLauncherAnimationController() { mLauncherLayoutListener.setHandler(this); onLauncherLayoutChanged(); + + // Mimic ActivityMetricsLogger.logAppTransitionMultiEvents() logging for + // "Recents" activity for app transition tests for the app-to-recents case. + final LogMaker builder = new LogMaker(761/*APP_TRANSITION*/); + builder.setPackageName("com.android.systemui"); + builder.addTaggedData(871/*FIELD_CLASS_NAME*/, + "com.android.systemui.recents.RecentsActivity"); + builder.addTaggedData(319/*APP_TRANSITION_DELAY_MS*/, + mLauncherFrameDrawnTime - mTouchTimeMs); + mMetricsLogger.write(builder); } public void updateInteractionType(@InteractionType int interactionType) { From 26a1b452f47f9fe4f1cfc700d98df8a3a569eac2 Mon Sep 17 00:00:00 2001 From: Derek Sollenberger Date: Fri, 23 Feb 2018 13:37:25 -0500 Subject: [PATCH 016/127] Stop using deprecated Canvas APIs. Bug: 73777445 Test: compile Change-Id: Ic0a1f4ebc10ba46229fd97408c052c0b450b4945 --- src/com/android/launcher3/badge/BadgeRenderer.java | 2 +- src/com/android/launcher3/dragndrop/DragView.java | 2 +- src/com/android/launcher3/folder/FolderIcon.java | 7 +++---- src/com/android/launcher3/folder/PreviewBackground.java | 5 ++--- src/com/android/launcher3/folder/PreviewItemManager.java | 2 +- .../android/launcher3/graphics/DragPreviewProvider.java | 2 +- src/com/android/launcher3/graphics/FixedScaleDrawable.java | 2 +- src/com/android/launcher3/graphics/LauncherIcons.java | 2 +- .../android/launcher3/graphics/PreloadIconDrawable.java | 2 +- .../launcher3/shortcuts/ShortcutDragPreviewProvider.java | 2 -- .../launcher3/views/DoubleShadowBubbleTextView.java | 4 ++-- .../android/launcher3/views/RecyclerViewFastScroller.java | 2 +- 12 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/com/android/launcher3/badge/BadgeRenderer.java b/src/com/android/launcher3/badge/BadgeRenderer.java index 72d49f02ff..948742727c 100644 --- a/src/com/android/launcher3/badge/BadgeRenderer.java +++ b/src/com/android/launcher3/badge/BadgeRenderer.java @@ -80,7 +80,7 @@ public class BadgeRenderer { Log.e(TAG, "Invalid null argument(s) passed in call to draw."); return; } - canvas.save(Canvas.MATRIX_SAVE_FLAG); + canvas.save(); // We draw the badge relative to its center. float badgeCenterX = iconBounds.right - mDotCenterOffset / 2; float badgeCenterY = iconBounds.top + mDotCenterOffset / 2; diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java index a59b8996b5..8d4f2ef0a3 100644 --- a/src/com/android/launcher3/dragndrop/DragView.java +++ b/src/com/android/launcher3/dragndrop/DragView.java @@ -448,7 +448,7 @@ public class DragView extends View { canvas.drawBitmap(mBitmap, 0.0f, 0.0f, mPaint); if (crossFade) { mPaint.setAlpha((int) (255 * mCrossFadeProgress)); - final int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG); + final int saveCount = canvas.save(); float sX = (mBitmap.getWidth() * 1.0f) / mCrossFadeBitmap.getWidth(); float sY = (mBitmap.getHeight() * 1.0f) / mCrossFadeBitmap.getHeight(); canvas.scale(sX, sY); diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java index 2de09b8f28..13926db691 100644 --- a/src/com/android/launcher3/folder/FolderIcon.java +++ b/src/com/android/launcher3/folder/FolderIcon.java @@ -467,11 +467,10 @@ public class FolderIcon extends FrameLayout implements FolderListener { final int saveCount; if (canvas.isHardwareAccelerated()) { - saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, - Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); + saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null); } else { - saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG); - canvas.clipPath(mBackground.getClipPath(), Region.Op.INTERSECT); + saveCount = canvas.save(); + canvas.clipPath(mBackground.getClipPath()); } mPreviewItemManager.draw(canvas); diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java index 285aef8c85..a0912a4a06 100644 --- a/src/com/android/launcher3/folder/PreviewBackground.java +++ b/src/com/android/launcher3/folder/PreviewBackground.java @@ -227,11 +227,10 @@ public class PreviewBackground { final int saveCount; if (canvas.isHardwareAccelerated()) { saveCount = canvas.saveLayer(offsetX - mStrokeWidth, offsetY, - offsetX + radius + shadowRadius, offsetY + shadowRadius + shadowRadius, - null, Canvas.CLIP_TO_LAYER_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG); + offsetX + radius + shadowRadius, offsetY + shadowRadius + shadowRadius, null); } else { - saveCount = canvas.save(Canvas.CLIP_SAVE_FLAG); + saveCount = canvas.save(); canvas.clipPath(getClipPath(), Region.Op.DIFFERENCE); } diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java index 06d3eb166b..1f69f6e768 100644 --- a/src/com/android/launcher3/folder/PreviewItemManager.java +++ b/src/com/android/launcher3/folder/PreviewItemManager.java @@ -168,7 +168,7 @@ public class PreviewItemManager { } private void drawPreviewItem(Canvas canvas, PreviewItemDrawingParams params) { - canvas.save(Canvas.MATRIX_SAVE_FLAG); + canvas.save(); canvas.translate(params.transX, params.transY); canvas.scale(params.scale, params.scale); Drawable d = params.drawable; diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java index 6a328e9230..b770785828 100644 --- a/src/com/android/launcher3/graphics/DragPreviewProvider.java +++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java @@ -103,7 +103,7 @@ public class DragPreviewProvider { } destCanvas.translate(-mView.getScrollX() + blurSizeOutline / 2, -mView.getScrollY() + blurSizeOutline / 2); - destCanvas.clipRect(clipRect, Op.REPLACE); + destCanvas.clipRect(clipRect); mView.draw(destCanvas); // Restore text visibility of FolderIcon if necessary diff --git a/src/com/android/launcher3/graphics/FixedScaleDrawable.java b/src/com/android/launcher3/graphics/FixedScaleDrawable.java index 262a95e2b0..0f0e42428d 100644 --- a/src/com/android/launcher3/graphics/FixedScaleDrawable.java +++ b/src/com/android/launcher3/graphics/FixedScaleDrawable.java @@ -29,7 +29,7 @@ public class FixedScaleDrawable extends DrawableWrapper { @Override public void draw(Canvas canvas) { - int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG); + int saveCount = canvas.save(); canvas.scale(mScaleX, mScaleY, getBounds().exactCenterX(), getBounds().exactCenterY()); super.draw(canvas); diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java index 34fc921a64..8abfdeae8e 100644 --- a/src/com/android/launcher3/graphics/LauncherIcons.java +++ b/src/com/android/launcher3/graphics/LauncherIcons.java @@ -302,7 +302,7 @@ public class LauncherIcons implements AutoCloseable { } else { icon.setBounds(left, top, left+width, top+height); } - mCanvas.save(Canvas.MATRIX_SAVE_FLAG); + mCanvas.save(); mCanvas.scale(scale, scale, textureWidth / 2, textureHeight / 2); icon.draw(mCanvas); mCanvas.restore(); diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java index a40b6df93b..ea55ba441f 100644 --- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java +++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java @@ -176,7 +176,7 @@ public class PreloadIconDrawable extends FastBitmapDrawable { } canvas.drawPath(mScaledProgressPath, mProgressPaint); - int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG); + int saveCount = canvas.save(); Rect bounds = getBounds(); canvas.scale(mIconScale, mIconScale, bounds.exactCenterX(), bounds.exactCenterY()); diff --git a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java index cfb9258dd9..ee97641109 100644 --- a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java +++ b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java @@ -50,12 +50,10 @@ public class ShortcutDragPreviewProvider extends DragPreviewProvider { Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(b); - canvas.save(Canvas.MATRIX_SAVE_FLAG); canvas.translate(blurSizeOutline / 2, blurSizeOutline / 2); canvas.scale(((float) size) / bounds.width(), ((float) size) / bounds.height(), 0, 0); canvas.translate(bounds.left, bounds.top); d.draw(canvas); - canvas.restore(); return b; } diff --git a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java index c8203f7f23..01b63bec47 100644 --- a/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java +++ b/src/com/android/launcher3/views/DoubleShadowBubbleTextView.java @@ -63,10 +63,10 @@ public class DoubleShadowBubbleTextView extends BubbleTextView { ColorUtils.setAlphaComponent(mShadowInfo.ambientShadowColor, alpha)); drawWithoutBadge(canvas); - canvas.save(Canvas.CLIP_SAVE_FLAG); + canvas.save(); canvas.clipRect(getScrollX(), getScrollY() + getExtendedPaddingTop(), getScrollX() + getWidth(), - getScrollY() + getHeight(), Region.Op.INTERSECT); + getScrollY() + getHeight()); getPaint().setShadowLayer(mShadowInfo.keyShadowBlur, 0.0f, mShadowInfo.keyShadowOffset, ColorUtils.setAlphaComponent(mShadowInfo.keyShadowColor, alpha)); diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java index fc121d3618..58c9148030 100644 --- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java +++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java @@ -289,7 +289,7 @@ public class RecyclerViewFastScroller extends View { if (mThumbOffsetY < 0) { return; } - int saveCount = canvas.save(Canvas.MATRIX_SAVE_FLAG); + int saveCount = canvas.save(); canvas.translate(getWidth() / 2, mRv.getScrollBarTop()); // Draw the track float halfW = mWidth / 2; From f58e0df0abd7afecbc9776f0a7e696fb22c062b8 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 1 Mar 2018 10:24:20 -0800 Subject: [PATCH 017/127] Skipping resetting transition if the same transition is running Bug: 73838765 Change-Id: I1a428f1b5d5b04397a317e0f35f3effb53c24405 --- .../launcher3/LauncherStateManager.java | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java index 2f8687d7e1..d5813f35d1 100644 --- a/src/com/android/launcher3/LauncherStateManager.java +++ b/src/com/android/launcher3/LauncherStateManager.java @@ -162,13 +162,26 @@ public class LauncherStateManager { } public void goToState(LauncherState state, boolean animated, long delay, long overrideDuration, - Runnable onCompleteRunnable) { - if (mLauncher.isInState(state) && mConfig.mCurrentAnimation == null) { - // Run any queued runnable - if (onCompleteRunnable != null) { - onCompleteRunnable.run(); + final Runnable onCompleteRunnable) { + if (mLauncher.isInState(state)) { + if (mConfig.mCurrentAnimation == null) { + // Run any queued runnable + if (onCompleteRunnable != null) { + onCompleteRunnable.run(); + } + return; + } else if (!mConfig.userControlled && animated) { + // We are running the same animation as requested + if (onCompleteRunnable != null) { + mConfig.mCurrentAnimation.addListener(new AnimationSuccessListener() { + @Override + public void onAnimationSuccess(Animator animator) { + onCompleteRunnable.run(); + } + }); + } + return; } - return; } // Cancel the current animation From 2c3eafcb26a526be55c37bd4deee940f529d81b5 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 1 Mar 2018 10:46:55 -0800 Subject: [PATCH 018/127] Defining an action for touch service so that the component name does not need to be hardcoded Also preventing the service behind system permission Change-Id: Ibb3f0d8115b2355b2f5b5ee991858f6377037e45 --- quickstep/AndroidManifest.xml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml index 02b4379bf6..d531a463b0 100644 --- a/quickstep/AndroidManifest.xml +++ b/quickstep/AndroidManifest.xml @@ -36,8 +36,13 @@ android:restoreAnyVersion="true" android:supportsRtl="true" > - + + + + + From 6639a5dfe0565f413c78e46c125f55333e8a9111 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 28 Feb 2018 15:09:36 -0800 Subject: [PATCH 019/127] Updating the scrim and landscpae ui > Instead of views, using a custom class to draw the color scrims > All-apps has full screen UI > Quickstep does not have search box in landscape Bug: 73085356 Change-Id: I360a78a2ade0134daad29fe712796cd39a381fbb --- quickstep/res/values/dimens.xml | 4 +- .../launcher3/uioverrides/AllAppsState.java | 3 +- .../uioverrides/OptionsPopupView.java | 16 +- .../launcher3/uioverrides/OverviewState.java | 20 +- .../com/android/quickstep/RecentsView.java | 11 +- res/layout/launcher.xml | 5 - res/layout/widgets_bottom_sheet_scrim.xml | 23 -- res/layout/widgets_full_sheet.xml | 5 - res/values/config.xml | 3 + src/com/android/launcher3/Launcher.java | 2 +- src/com/android/launcher3/LauncherState.java | 8 + src/com/android/launcher3/Workspace.java | 7 +- .../WorkspaceStateTransitionAnimation.java | 13 +- .../allapps/AllAppsContainerView.java | 8 + .../allapps/AllAppsTransitionController.java | 30 +-- .../launcher3/dragndrop/DragLayer.java | 36 +-- .../dragndrop/PageCutOutScrimDrawable.java | 90 ------- .../dynamicui/WallpaperColorInfo.java | 1 - .../launcher3/graphics/ColorScrim.java | 64 +++++ .../launcher3/graphics/GradientView.java | 198 --------------- .../android/launcher3/graphics/ViewScrim.java | 77 ++++++ .../graphics/WorkspaceAndHotseatScrim.java | 152 ++++++++++++ .../launcher3/states/SpringLoadedState.java | 2 +- .../android/launcher3/views/AllAppsScrim.java | 233 ------------------ .../launcher3/widget/BaseWidgetSheet.java | 7 +- .../launcher3/widget/WidgetsBottomSheet.java | 12 - .../launcher3/widget/WidgetsFullSheet.java | 23 +- .../launcher3/uioverrides/AllAppsState.java | 3 +- .../launcher3/uioverrides/OverviewState.java | 2 +- 29 files changed, 375 insertions(+), 683 deletions(-) delete mode 100644 res/layout/widgets_bottom_sheet_scrim.xml delete mode 100644 src/com/android/launcher3/dragndrop/PageCutOutScrimDrawable.java create mode 100644 src/com/android/launcher3/graphics/ColorScrim.java delete mode 100644 src/com/android/launcher3/graphics/GradientView.java create mode 100644 src/com/android/launcher3/graphics/ViewScrim.java create mode 100644 src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java delete mode 100644 src/com/android/launcher3/views/AllAppsScrim.java diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index 9b6c0535c7..cf86176201 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -24,6 +24,7 @@ 2dp 20dp 10dp + 100dp @@ -34,9 +35,6 @@ -24dp - - 90dp - 25dp 80dp diff --git a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java index 426fe35efb..ea03a7684c 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java @@ -32,7 +32,8 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; */ public class AllAppsState extends LauncherState { - private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY; + private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY + | FLAG_SHOW_SCRIM | FLAG_ALL_APPS_SCRIM; private static final PageAlphaProvider PAGE_ALPHA_PROVIDER = new PageAlphaProvider(DEACCEL_2) { @Override diff --git a/quickstep/src/com/android/launcher3/uioverrides/OptionsPopupView.java b/quickstep/src/com/android/launcher3/uioverrides/OptionsPopupView.java index c089d063f3..ccdcbede6e 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/OptionsPopupView.java +++ b/quickstep/src/com/android/launcher3/uioverrides/OptionsPopupView.java @@ -42,7 +42,7 @@ import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.RevealOutlineAnimation; import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; import com.android.launcher3.dragndrop.DragLayer; -import com.android.launcher3.graphics.GradientView; +import com.android.launcher3.graphics.ColorScrim; import com.android.launcher3.widget.WidgetsFullSheet; /** @@ -54,7 +54,7 @@ public class OptionsPopupView extends AbstractFloatingView implements OnClickLis private final Launcher mLauncher; private final PointF mTouchPoint = new PointF(); - private final GradientView mGradientView; + private final ColorScrim mScrim; protected Animator mOpenCloseAnimator; @@ -75,11 +75,7 @@ public class OptionsPopupView extends AbstractFloatingView implements OnClickLis }); mLauncher = Launcher.getLauncher(context); - - mGradientView = (GradientView) mLauncher.getLayoutInflater().inflate( - R.layout.widgets_bottom_sheet_scrim, mLauncher.getDragLayer(), false); - mGradientView.setProgress(1, false); - mGradientView.setAlpha(0); + mScrim = ColorScrim.createExtractedColorScrim(this); } @Override @@ -149,7 +145,7 @@ public class OptionsPopupView extends AbstractFloatingView implements OnClickLis fadeOut.setInterpolator(Interpolators.DEACCEL); closeAnim.play(fadeOut); - Animator gradientAlpha = ObjectAnimator.ofFloat(mGradientView, ALPHA, 0); + Animator gradientAlpha = ObjectAnimator.ofFloat(mScrim, ColorScrim.PROGRESS, 0); gradientAlpha.setInterpolator(Interpolators.DEACCEL); closeAnim.play(gradientAlpha); @@ -177,7 +173,6 @@ public class OptionsPopupView extends AbstractFloatingView implements OnClickLis } mIsOpen = false; mLauncher.getDragLayer().removeView(this); - mLauncher.getDragLayer().removeView(mGradientView); } @Override @@ -213,7 +208,7 @@ public class OptionsPopupView extends AbstractFloatingView implements OnClickLis .createRevealAnimator(this, false); openAnim.play(revealAnim); - Animator gradientAlpha = ObjectAnimator.ofFloat(mGradientView, ALPHA, 1); + Animator gradientAlpha = ObjectAnimator.ofFloat(mScrim, ColorScrim.PROGRESS, 1); gradientAlpha.setInterpolator(Interpolators.ACCEL); openAnim.play(gradientAlpha); @@ -269,7 +264,6 @@ public class OptionsPopupView extends AbstractFloatingView implements OnClickLis lp.y = Utilities.boundToRange((int) (y - height / 2), insets.top + margin, maxHeight - insets.bottom - height - margin); - launcher.getDragLayer().addView(view.mGradientView); launcher.getDragLayer().addView(view); view.animateOpen(); } diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java index 613968ecd8..77fb842043 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java @@ -18,11 +18,9 @@ package com.android.launcher3.uioverrides; import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS; import static com.android.launcher3.anim.Interpolators.ACCEL_2; -import android.content.Context; import android.graphics.Rect; import android.view.View; -import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; @@ -36,7 +34,7 @@ import com.android.quickstep.RecentsView; public class OverviewState extends LauncherState { private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED - | FLAG_DISABLE_RESTORE; + | FLAG_DISABLE_RESTORE | FLAG_PAGE_BACKGROUNDS; public OverviewState(int id) { super(id, ContainerType.TASKSWITCHER, OVERVIEW_TRANSITION_MS, STATE_FLAGS); @@ -71,11 +69,6 @@ public class OverviewState extends LauncherState { rv.setOverviewStateEnabled(false); } - @Override - public float getVerticalProgress(Launcher launcher) { - return getVerticalProgress(launcher.getDeviceProfile(), launcher); - } - @Override public View getFinalFocus(Launcher launcher) { return launcher.getOverviewPanel(); @@ -118,15 +111,4 @@ public class OverviewState extends LauncherState { return new float[] {scale, translationX, translationY}; } - - public static float getVerticalProgress(DeviceProfile grid, Context context) { - if (!grid.isVerticalBarLayout()) { - return 1f; - } - - float total = grid.heightPx; - float searchHeight = total - grid.availableHeightPx + - context.getResources().getDimension(R.dimen.all_apps_search_box_full_height); - return 1 - (searchHeight / total); - } } diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java index 42677c170b..0d9e2a7683 100644 --- a/quickstep/src/com/android/quickstep/RecentsView.java +++ b/quickstep/src/com/android/quickstep/RecentsView.java @@ -383,11 +383,14 @@ public class RecentsView extends PagedView implements Insettable, OnSharedPrefer float overviewHeight, overviewWidth; if (profile.isVerticalBarLayout()) { + float scrimLength = context.getResources() + .getDimension(R.dimen.recents_page_fade_length); + float maxPadding = Math.max(padding.left, padding.right); + // Use the same padding on both sides for symmetry. - float availableWidth = taskWidth - 2 * Math.max(padding.left, padding.right); - float availableHeight = profile.availableHeightPx - padding.top - - sTempStableInsets.top - Math.max(padding.bottom, - profile.heightPx * (1 - OverviewState.getVerticalProgress(profile, context))); + float availableWidth = taskWidth - 2 * Math.max(maxPadding, scrimLength); + float availableHeight = profile.availableHeightPx - padding.top - padding.bottom + - sTempStableInsets.top; float scaledRatio = Math.min(availableWidth / taskWidth, availableHeight / taskHeight); overviewHeight = taskHeight * scaledRatio; overviewWidth = taskWidth * scaledRatio; diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml index 314359b8b7..d07ff81073 100644 --- a/res/layout/launcher.xml +++ b/res/layout/launcher.xml @@ -44,11 +44,6 @@ layout="@layout/overview_panel" android:visibility="gone" /> - - - - - \ No newline at end of file diff --git a/res/layout/widgets_full_sheet.xml b/res/layout/widgets_full_sheet.xml index 20eca9f25d..ca397bd43b 100644 --- a/res/layout/widgets_full_sheet.xml +++ b/res/layout/widgets_full_sheet.xml @@ -20,11 +20,6 @@ android:orientation="vertical" android:theme="?attr/widgetsTheme" > - - + + + 150 80 diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 38b0140781..38235f45b9 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -1003,7 +1003,7 @@ public class Launcher extends BaseActivity mDragController.setMoveTarget(mWorkspace); mDropTargetBar.setup(mDragController); - mAllAppsController.setupViews(mAppsView, mHotseat, mWorkspace); + mAllAppsController.setupViews(mAppsView, mHotseat); } /** diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java index 472a5a95c2..402d73d498 100644 --- a/src/com/android/launcher3/LauncherState.java +++ b/src/com/android/launcher3/LauncherState.java @@ -44,6 +44,8 @@ public class LauncherState { protected static final int FLAG_DISABLE_RESTORE = 1 << 3; protected static final int FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED = 1 << 4; protected static final int FLAG_DISABLE_PAGE_CLIPPING = 1 << 5; + protected static final int FLAG_PAGE_BACKGROUNDS = 1 << 6; + protected static final int FLAG_ALL_APPS_SCRIM = 1 << 7; protected static final PageAlphaProvider DEFAULT_ALPHA_PROVIDER = new PageAlphaProvider(ACCEL_2) { @@ -96,6 +98,9 @@ public class LauncherState { * @see WorkspaceStateTransitionAnimation */ public final boolean hasScrim; + public final boolean hasWorkspacePageBackground; + public final boolean hasAllAppsScrim; + public final int transitionDuration; /** @@ -114,6 +119,9 @@ public class LauncherState { this.transitionDuration = transitionDuration; this.hasScrim = (flags & FLAG_SHOW_SCRIM) != 0; + this.hasWorkspacePageBackground = (flags & FLAG_PAGE_BACKGROUNDS) != 0; + this.hasAllAppsScrim = (flags & FLAG_ALL_APPS_SCRIM) != 0; + this.hasMultipleVisiblePages = (flags & FLAG_MULTI_PAGE) != 0; this.workspaceAccessibilityFlag = (flags & FLAG_DISABLE_ACCESSIBILITY) != 0 ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 141494614b..7c42b4800c 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -76,6 +76,8 @@ import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.folder.PreviewBackground; import com.android.launcher3.graphics.DragPreviewProvider; import com.android.launcher3.graphics.PreloadIconDrawable; +import com.android.launcher3.graphics.ViewScrim; +import com.android.launcher3.graphics.WorkspaceAndHotseatScrim; import com.android.launcher3.pageindicators.WorkspacePageIndicator; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider; @@ -280,6 +282,9 @@ public class Workspace extends PagedView // Disable multitouch across the workspace/all apps/customize tray setMotionEventSplittingEnabled(true); + + // Attach a scrim + new WorkspaceAndHotseatScrim(this).attach(); } @Override @@ -2229,7 +2234,7 @@ public class Workspace extends PagedView } // Invalidating the scrim will also force this CellLayout // to be invalidated so that it is highlighted if necessary. - mLauncher.getDragLayer().invalidateScrim(); + ViewScrim.get(this).invalidate(); } public CellLayout getCurrentDragOverlappingLayout() { diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index 21f5d671ee..77ac9de35c 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -32,6 +32,7 @@ import com.android.launcher3.LauncherState.PageAlphaProvider; import com.android.launcher3.LauncherStateManager.AnimationConfig; import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.graphics.ViewScrim; /** * A convenience class to update a view's visibility state after an alpha animation. @@ -90,8 +91,6 @@ public class WorkspaceStateTransitionAnimation { public static final PropertySetter NO_ANIM_PROPERTY_SETTER = new PropertySetter(); - public final int mWorkspaceScrimAlpha; - private final Launcher mLauncher; private final Workspace mWorkspace; @@ -100,8 +99,6 @@ public class WorkspaceStateTransitionAnimation { public WorkspaceStateTransitionAnimation(Launcher launcher, Workspace workspace) { mLauncher = launcher; mWorkspace = workspace; - mWorkspaceScrimAlpha = launcher.getResources() - .getInteger(R.integer.config_workspaceScrimAlpha); } public void setState(LauncherState toState) { @@ -142,8 +139,10 @@ public class WorkspaceStateTransitionAnimation { pageAlphaProvider.interpolator); // Set scrim - propertySetter.setInt(mLauncher.getDragLayer().getScrim(), DRAWABLE_ALPHA, - state.hasScrim ? mWorkspaceScrimAlpha : 0, Interpolators.DEACCEL_1_5); + propertySetter.setFloat(ViewScrim.get(mWorkspace), ViewScrim.PROGRESS, + state.hasScrim ? 1 : 0, Interpolators.LINEAR); + propertySetter.setFloat(ViewScrim.get(mLauncher.getAppsView()), ViewScrim.PROGRESS, + state.hasAllAppsScrim ? 1 : 0, Interpolators.LINEAR); } public void applyChildState(LauncherState state, CellLayout cl, int childIndex) { @@ -154,7 +153,7 @@ public class WorkspaceStateTransitionAnimation { private void applyChildState(LauncherState state, CellLayout cl, int childIndex, PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter) { float pageAlpha = pageAlphaProvider.getPageAlpha(childIndex); - int drawableAlpha = Math.round(pageAlpha * (state.hasScrim ? 255 : 0)); + int drawableAlpha = Math.round(pageAlpha * (state.hasWorkspacePageBackground ? 255 : 0)); propertySetter.setInt(cl.getScrimBackground(), DRAWABLE_ALPHA, drawableAlpha, Interpolators.ZOOM_IN); diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index a7eae39ff3..82bdef977e 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -15,6 +15,8 @@ */ package com.android.launcher3.allapps; +import static com.android.launcher3.anim.Interpolators.DEACCEL_2; + import android.content.Context; import android.graphics.Bitmap; import android.graphics.Rect; @@ -53,9 +55,11 @@ import com.android.launcher3.anim.SpringAnimationHandler; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; +import com.android.launcher3.graphics.ColorScrim; import com.android.launcher3.keyboard.FocusedItemDecorator; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.util.ItemInfoMatcher; +import com.android.launcher3.util.Themes; import com.android.launcher3.views.BottomUserEducationView; /** @@ -110,6 +114,10 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource, mAH[AdapterHolder.WORK] = new AdapterHolder(true /* isWork */); mAllAppsStore.addUpdateListener(this::onAppsUpdated); + + // Attach a scrim to be drawn behind all-apps and hotseat + new ColorScrim(this, Themes.getAttrColor(context, R.attr.allAppsScrimColor), DEACCEL_2) + .attach(); } @Override diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index c859347d80..13a42f1d37 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -16,17 +16,14 @@ import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.Hotseat; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; -import com.android.launcher3.LauncherStateManager; import com.android.launcher3.LauncherStateManager.AnimationConfig; import com.android.launcher3.LauncherStateManager.StateHandler; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.Workspace; import com.android.launcher3.allapps.SearchUiManager.OnScrollRangeChangeListener; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.util.Themes; -import com.android.launcher3.views.AllAppsScrim; /** * Handles AllApps view transition. @@ -58,7 +55,6 @@ public class AllAppsTransitionController public static final float PARALLAX_COEFFICIENT = .125f; private AllAppsContainerView mAppsView; - private Workspace mWorkspace; private Hotseat mHotseat; private final Launcher mLauncher; @@ -76,8 +72,6 @@ public class AllAppsTransitionController private static final float DEFAULT_SHIFT_RANGE = 10; - private AllAppsScrim mAllAppsScrim; - public AllAppsTransitionController(Launcher l) { mLauncher = l; mShiftRange = DEFAULT_SHIFT_RANGE; @@ -106,7 +100,6 @@ public class AllAppsTransitionController mAppsView.setAlpha(1); mLauncher.getHotseat().setTranslationY(0); mLauncher.getWorkspace().getPageIndicator().setTranslationY(0); - mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, 0); } } @@ -127,25 +120,21 @@ public class AllAppsTransitionController float alpha = 1 - workspaceHotseatAlpha; mAppsView.setTranslationY(shiftCurrent); - if (mAllAppsScrim == null) { - mAllAppsScrim = mLauncher.findViewById(R.id.all_apps_scrim); - } float hotseatTranslation = -mShiftRange + shiftCurrent; - mAllAppsScrim.setProgress(hotseatTranslation, alpha); if (!mIsVerticalLayout) { mAppsView.setAlpha(alpha); mLauncher.getHotseat().setTranslationY(hotseatTranslation); mLauncher.getWorkspace().getPageIndicator().setTranslationY(hotseatTranslation); + } - // Use a light system UI (dark icons) if all apps is behind at least half of the - // status bar. - boolean forceChange = shiftCurrent <= mShiftRange / 4; - if (forceChange) { - mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, !mIsDarkTheme); - } else { - mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, 0); - } + // Use a light system UI (dark icons) if all apps is behind at least half of the + // status bar. + boolean forceChange = shiftCurrent <= mShiftRange / 4; + if (forceChange) { + mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, !mIsDarkTheme); + } else { + mLauncher.getSystemUiController().updateUiState(UI_STATE_ALL_APPS, 0); } } @@ -201,10 +190,9 @@ public class AllAppsTransitionController }; } - public void setupViews(AllAppsContainerView appsView, Hotseat hotseat, Workspace workspace) { + public void setupViews(AllAppsContainerView appsView, Hotseat hotseat) { mAppsView = appsView; mHotseat = hotseat; - mWorkspace = workspace; mHotseat.bringToFront(); mAppsView.getSearchUiManager().addOnScrollRangeChangeListener(this); } diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java index 1cf407eb95..7e3335ac3d 100644 --- a/src/com/android/launcher3/dragndrop/DragLayer.java +++ b/src/com/android/launcher3/dragndrop/DragLayer.java @@ -27,7 +27,6 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Rect; -import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.MotionEvent; @@ -50,6 +49,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderIcon; +import com.android.launcher3.graphics.ViewScrim; import com.android.launcher3.keyboard.ViewGroupFocusHelper; import com.android.launcher3.uioverrides.UiFactory; import com.android.launcher3.util.Thunk; @@ -88,7 +88,6 @@ public class DragLayer extends InsettableFrameLayout { // Related to adjacent page hints private final ViewGroupFocusHelper mFocusIndicatorHelper; - private final PageCutOutScrimDrawable mPageCutOutScrim; protected TouchController[] mControllers; private TouchController mActiveController; @@ -106,8 +105,6 @@ public class DragLayer extends InsettableFrameLayout { setChildrenDrawingOrderEnabled(true); mFocusIndicatorHelper = new ViewGroupFocusHelper(this); - mPageCutOutScrim = new PageCutOutScrimDrawable(this); - mPageCutOutScrim.setCallback(this); } public void setup(Launcher launcher, DragController dragController) { @@ -125,11 +122,6 @@ public class DragLayer extends InsettableFrameLayout { return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event); } - @Override - protected boolean verifyDrawable(Drawable who) { - return super.verifyDrawable(who) || who == mPageCutOutScrim; - } - public boolean isEventOverHotseat(MotionEvent ev) { return isEventOverView(mLauncher.getHotseat(), ev); } @@ -147,6 +139,15 @@ public class DragLayer extends InsettableFrameLayout { return mHitRect.contains((int) ev.getX(), (int) ev.getY()); } + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + ViewScrim scrim = ViewScrim.get(child); + if (scrim != null) { + scrim.draw(canvas, getWidth(), getHeight()); + } + return super.drawChild(canvas, child, drawingTime); + } + @Override public boolean onInterceptTouchEvent(MotionEvent ev) { int action = ev.getAction(); @@ -536,11 +537,7 @@ public class DragLayer extends InsettableFrameLayout { final int fromX = r.left; final int fromY = r.top; child.setVisibility(INVISIBLE); - Runnable onCompleteRunnable = new Runnable() { - public void run() { - child.setVisibility(VISIBLE); - } - }; + Runnable onCompleteRunnable = () -> child.setVisibility(VISIBLE); animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, toScale, toScale, onCompleteRunnable, ANIMATION_END_DISAPPEAR, duration, anchorView); } @@ -758,20 +755,9 @@ public class DragLayer extends InsettableFrameLayout { } } - public void invalidateScrim() { - if (mPageCutOutScrim.getAlpha() > 0) { - invalidate(); - } - } - - public Drawable getScrim() { - return mPageCutOutScrim; - } - @Override protected void dispatchDraw(Canvas canvas) { // Draw the background below children. - mPageCutOutScrim.draw(canvas); mFocusIndicatorHelper.draw(canvas); super.dispatchDraw(canvas); } diff --git a/src/com/android/launcher3/dragndrop/PageCutOutScrimDrawable.java b/src/com/android/launcher3/dragndrop/PageCutOutScrimDrawable.java deleted file mode 100644 index 367124b5dd..0000000000 --- a/src/com/android/launcher3/dragndrop/PageCutOutScrimDrawable.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3.dragndrop; - -import android.graphics.Canvas; -import android.graphics.ColorFilter; -import android.graphics.PixelFormat; -import android.graphics.Rect; -import android.graphics.Region; -import android.graphics.drawable.Drawable; -import android.support.v4.graphics.ColorUtils; - -import com.android.launcher3.CellLayout; -import com.android.launcher3.Launcher; -import com.android.launcher3.dynamicui.WallpaperColorInfo; - -/** - * Scrim drawable which draws a hole for the current drop target page. - */ -public class PageCutOutScrimDrawable extends Drawable { - - private final Rect mHighlightRect = new Rect(); - private final DragLayer mDragLayer; - private final Launcher mLauncher; - private final WallpaperColorInfo mWallpaperColorInfo; - - private int mAlpha = 0; - - public PageCutOutScrimDrawable(DragLayer dragLayer) { - mDragLayer = dragLayer; - mLauncher = Launcher.getLauncher(mDragLayer.getContext()); - mWallpaperColorInfo = WallpaperColorInfo.getInstance(mLauncher); - } - - @Override - public void draw(Canvas canvas) { - // Draw the background below children. - if (mAlpha > 0) { - // Update the scroll position first to ensure scrim cutout is in the right place. - mLauncher.getWorkspace().computeScrollWithoutInvalidation(); - CellLayout currCellLayout = mLauncher.getWorkspace().getCurrentDragOverlappingLayout(); - canvas.save(); - if (currCellLayout != null && currCellLayout != mLauncher.getHotseat().getLayout()) { - // Cut a hole in the darkening scrim on the page that should be highlighted, if any. - mDragLayer.getDescendantRectRelativeToSelf(currCellLayout, mHighlightRect); - canvas.clipRect(mHighlightRect, Region.Op.DIFFERENCE); - } - // for super light wallpaper it needs to be darken for contrast to workspace - // for dark wallpapers the text is white so darkening works as well - int color = ColorUtils.compositeColors(0x66000000, mWallpaperColorInfo.getMainColor()); - canvas.drawColor(ColorUtils.setAlphaComponent(color, mAlpha)); - canvas.restore(); - } - } - - @Override - public void setAlpha(int alpha) { - if (mAlpha != alpha) { - mAlpha = alpha; - invalidateSelf(); - } - } - - @Override - public int getAlpha() { - return mAlpha; - } - - @Override - public void setColorFilter(ColorFilter colorFilter) { } - - @Override - public int getOpacity() { - return PixelFormat.TRANSLUCENT; - } -} diff --git a/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java b/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java index 80a89e37de..267e9301a7 100644 --- a/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java +++ b/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java @@ -2,7 +2,6 @@ package com.android.launcher3.dynamicui; import android.content.Context; import android.graphics.Color; -import android.support.v4.graphics.ColorUtils; import android.util.Pair; import com.android.launcher3.compat.WallpaperColorsCompat; diff --git a/src/com/android/launcher3/graphics/ColorScrim.java b/src/com/android/launcher3/graphics/ColorScrim.java new file mode 100644 index 0000000000..1ffce18232 --- /dev/null +++ b/src/com/android/launcher3/graphics/ColorScrim.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.graphics; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.support.v4.graphics.ColorUtils; +import android.view.View; +import android.view.animation.Interpolator; + +import com.android.launcher3.R; +import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.dynamicui.WallpaperColorInfo; + +/** + * Simple scrim which draws a color + */ +public class ColorScrim extends ViewScrim { + + private final int mColor; + private final Interpolator mInterpolator; + private int mCurrentColor; + + public ColorScrim(View view, int color, Interpolator interpolator) { + super(view); + mColor = color; + mInterpolator = interpolator; + } + + @Override + protected void onProgressChanged() { + mCurrentColor = ColorUtils.setAlphaComponent(mColor, + Math.round(mInterpolator.getInterpolation(mProgress) * Color.alpha(mColor))); + } + + @Override + public void draw(Canvas canvas, int width, int height) { + if (mProgress > 0) { + canvas.drawColor(mCurrentColor); + } + } + + public static ColorScrim createExtractedColorScrim(View view) { + WallpaperColorInfo colors = WallpaperColorInfo.getInstance(view.getContext()); + int alpha = view.getResources().getInteger(R.integer.extracted_color_gradient_alpha); + ColorScrim scrim = new ColorScrim(view, ColorUtils.setAlphaComponent( + colors.getSecondaryColor(), alpha), Interpolators.LINEAR); + scrim.attach(); + return scrim; + } +} diff --git a/src/com/android/launcher3/graphics/GradientView.java b/src/com/android/launcher3/graphics/GradientView.java deleted file mode 100644 index 6253e18072..0000000000 --- a/src/com/android/launcher3/graphics/GradientView.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3.graphics; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.LinearGradient; -import android.graphics.Paint; -import android.graphics.RadialGradient; -import android.graphics.RectF; -import android.graphics.Shader; -import android.support.v4.graphics.ColorUtils; -import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.view.View; -import android.view.animation.Interpolator; - -import com.android.launcher3.Launcher; -import com.android.launcher3.R; -import com.android.launcher3.Utilities; -import com.android.launcher3.anim.Interpolators; -import com.android.launcher3.dynamicui.WallpaperColorInfo; -import com.android.launcher3.util.Themes; - -/** - * Draws a translucent radial gradient background from an initial state with progress 0.0 to a - * final state with progress 1.0; - */ -public class GradientView extends View implements WallpaperColorInfo.OnChangeListener { - - private static final int DEFAULT_COLOR = Color.WHITE; - private static final int ALPHA_MASK_HEIGHT_DP = 500; - private static final int ALPHA_MASK_WIDTH_DP = 2; - private static final boolean DEBUG = false; - - private final Bitmap mAlphaGradientMask; - - private boolean mShowScrim = true; - private int mColor1 = DEFAULT_COLOR; - private int mColor2 = DEFAULT_COLOR; - private int mWidth; - private int mHeight; - private final RectF mAlphaMaskRect = new RectF(); - private final RectF mFinalMaskRect = new RectF(); - private final Paint mPaintWithScrim = new Paint(); - private final Paint mPaintNoScrim = new Paint(); - private float mProgress; - private final int mMaskHeight, mMaskWidth; - private final int mAlphaColors; - private final Paint mDebugPaint = DEBUG ? new Paint() : null; - private final Interpolator mAccelerator = Interpolators.ACCEL; - private final float mAlphaStart; - private final WallpaperColorInfo mWallpaperColorInfo; - private final int mScrimColor; - - public GradientView(Context context, AttributeSet attrs) { - super(context, attrs); - DisplayMetrics dm = getResources().getDisplayMetrics(); - this.mMaskHeight = Utilities.pxFromDp(ALPHA_MASK_HEIGHT_DP, dm); - this.mMaskWidth = Utilities.pxFromDp(ALPHA_MASK_WIDTH_DP, dm); - Launcher launcher = Launcher.getLauncher(context); - this.mAlphaStart = 0; - this.mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor); - this.mWallpaperColorInfo = WallpaperColorInfo.getInstance(launcher); - mAlphaColors = getResources().getInteger(R.integer.extracted_color_gradient_alpha); - updateColors(); - mAlphaGradientMask = createDitheredAlphaMask(); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mWallpaperColorInfo.addOnChangeListener(this); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mWallpaperColorInfo.removeOnChangeListener(this); - } - - @Override - public void onExtractedColorsChanged(WallpaperColorInfo info) { - updateColors(); - invalidate(); - } - - private void updateColors() { - this.mColor1 = ColorUtils.setAlphaComponent(mWallpaperColorInfo.getMainColor(), - mAlphaColors); - this.mColor2 = ColorUtils.setAlphaComponent(mWallpaperColorInfo.getSecondaryColor(), - mAlphaColors); - if (mWidth + mHeight > 0) { - createRadialShader(); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - this.mWidth = getMeasuredWidth(); - this.mHeight = getMeasuredHeight(); - if (mWidth + mHeight > 0) { - createRadialShader(); - } - } - - // only being called when colors change - private void createRadialShader() { - final float gradientCenterY = 1.05f; - float radius = Math.max(mHeight, mWidth) * gradientCenterY; - float posScreenBottom = (radius - mHeight) / radius; // center lives below screen - - RadialGradient shaderNoScrim = new RadialGradient( - mWidth * 0.5f, - mHeight * gradientCenterY, - radius, - new int[] {mColor1, mColor1, mColor2}, - new float[] {0f, posScreenBottom, 1f}, - Shader.TileMode.CLAMP); - mPaintNoScrim.setShader(shaderNoScrim); - - int color1 = ColorUtils.compositeColors(mScrimColor,mColor1); - int color2 = ColorUtils.compositeColors(mScrimColor,mColor2); - RadialGradient shaderWithScrim = new RadialGradient( - mWidth * 0.5f, - mHeight * gradientCenterY, - radius, - new int[] { color1, color1, color2 }, - new float[] {0f, posScreenBottom, 1f}, - Shader.TileMode.CLAMP); - mPaintWithScrim.setShader(shaderWithScrim); - } - - public void setProgress(float progress) { - setProgress(progress, true); - } - - public void setProgress(float progress, boolean showScrim) { - this.mProgress = progress; - this.mShowScrim = showScrim; - invalidate(); - } - - @Override - protected void onDraw(Canvas canvas) { - Paint paint = mShowScrim ? mPaintWithScrim : mPaintNoScrim; - - float head = 0.29f; - float linearProgress = head + (mProgress * (1f - head)); - float startMaskY = (1f - linearProgress) * mHeight - mMaskHeight * linearProgress; - float interpolatedAlpha = (255 - mAlphaStart) * mAccelerator.getInterpolation(mProgress); - paint.setAlpha((int) (mAlphaStart + interpolatedAlpha)); - float div = (float) Math.floor(startMaskY + mMaskHeight); - mAlphaMaskRect.set(0, startMaskY, mWidth, div); - mFinalMaskRect.set(0, div, mWidth, mHeight); - canvas.drawBitmap(mAlphaGradientMask, null, mAlphaMaskRect, paint); - canvas.drawRect(mFinalMaskRect, paint); - - if (DEBUG) { - mDebugPaint.setColor(0xFF00FF00); - canvas.drawLine(0, startMaskY, mWidth, startMaskY, mDebugPaint); - canvas.drawLine(0, startMaskY + mMaskHeight, mWidth, startMaskY + mMaskHeight, mDebugPaint); - } - } - - public Bitmap createDitheredAlphaMask() { - Bitmap dst = Bitmap.createBitmap(mMaskWidth, mMaskHeight, Bitmap.Config.ALPHA_8); - Canvas c = new Canvas(dst); - Paint paint = new Paint(Paint.DITHER_FLAG); - LinearGradient lg = new LinearGradient(0, 0, 0, mMaskHeight, - new int[]{ - 0x00FFFFFF, - ColorUtils.setAlphaComponent(Color.WHITE, (int) (0xFF * 0.95)), - 0xFFFFFFFF}, - new float[]{0f, 0.8f, 1f}, - Shader.TileMode.CLAMP); - paint.setShader(lg); - c.drawRect(0, 0, mMaskWidth, mMaskHeight, paint); - return dst; - } -} \ No newline at end of file diff --git a/src/com/android/launcher3/graphics/ViewScrim.java b/src/com/android/launcher3/graphics/ViewScrim.java new file mode 100644 index 0000000000..e1727e0e5b --- /dev/null +++ b/src/com/android/launcher3/graphics/ViewScrim.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.graphics; + +import android.graphics.Canvas; +import android.util.Property; +import android.view.View; +import android.view.ViewParent; + +import com.android.launcher3.R; + +/** + * A utility class that can be used to draw a scrim behind a view + */ +public abstract class ViewScrim { + + public static Property PROGRESS = + new Property(Float.TYPE, "progress") { + @Override + public Float get(ViewScrim viewScrim) { + return viewScrim.mProgress; + } + + @Override + public void set(ViewScrim object, Float value) { + object.setProgress(value); + } + }; + + protected final T mView; + protected float mProgress = 0; + + public ViewScrim(T view) { + mView = view; + } + + public void attach() { + mView.setTag(R.id.view_scrim, this); + } + + public void setProgress(float progress) { + if (mProgress != progress) { + mProgress = progress; + onProgressChanged(); + invalidate(); + } + } + + public abstract void draw(Canvas canvas, int width, int height); + + protected void onProgressChanged() { } + + public void invalidate() { + ViewParent parent = mView.getParent(); + if (parent != null) { + ((View) parent).invalidate(); + } + } + + public static ViewScrim get(View view) { + return (ViewScrim) view.getTag(R.id.view_scrim); + } +} diff --git a/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java b/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java new file mode 100644 index 0000000000..2318a778bb --- /dev/null +++ b/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.graphics; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.LinearGradient; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Region; +import android.graphics.Shader; +import android.support.v4.graphics.ColorUtils; +import android.util.DisplayMetrics; +import android.view.View; + +import com.android.launcher3.CellLayout; +import com.android.launcher3.Launcher; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.Workspace; +import com.android.launcher3.dynamicui.WallpaperColorInfo; + +/** + * View scrim which draws behind hotseat and workspace + */ +public class WorkspaceAndHotseatScrim extends ViewScrim implements + View.OnAttachStateChangeListener, WallpaperColorInfo.OnChangeListener { + + private static final int DARK_SCRIM_COLOR = 0x55000000; + private static final int MAX_HOTSEAT_SCRIM_ALPHA = 100; + private static final int ALPHA_MASK_HEIGHT_DP = 500; + private static final int ALPHA_MASK_BITMAP_DP = 200; + private static final int ALPHA_MASK_WIDTH_DP = 2; + + private final Rect mHighlightRect = new Rect(); + private final Launcher mLauncher; + private final WallpaperColorInfo mWallpaperColorInfo; + + private final boolean mHasHotseatScrim; + private final RectF mFinalMaskRect = new RectF(); + private final Paint mBottomMaskPaint = new Paint(Paint.FILTER_BITMAP_FLAG); + + private final Bitmap mBottomMask; + private final int mMaskHeight; + + private int mFullScrimColor; + + private final int mMaxAlpha; + private int mAlpha = 0; + + public WorkspaceAndHotseatScrim(Workspace view) { + super(view); + mLauncher = Launcher.getLauncher(view.getContext()); + mWallpaperColorInfo = WallpaperColorInfo.getInstance(mLauncher); + + mMaxAlpha = mLauncher.getResources().getInteger(R.integer.config_workspaceScrimAlpha); + mMaskHeight = Utilities.pxFromDp(ALPHA_MASK_BITMAP_DP, + view.getResources().getDisplayMetrics()); + + mHasHotseatScrim = !mWallpaperColorInfo.supportsDarkText(); + mBottomMask = mHasHotseatScrim ? createDitheredAlphaMask() : null; + + view.addOnAttachStateChangeListener(this); + onExtractedColorsChanged(mWallpaperColorInfo); + } + + @Override + public void draw(Canvas canvas, int width, int height) { + // Draw the background below children. + if (mAlpha > 0) { + // Update the scroll position first to ensure scrim cutout is in the right place. + mView.computeScrollWithoutInvalidation(); + CellLayout currCellLayout = mView.getCurrentDragOverlappingLayout(); + canvas.save(); + if (currCellLayout != null && currCellLayout != mLauncher.getHotseat().getLayout()) { + // Cut a hole in the darkening scrim on the page that should be highlighted, if any. + mLauncher.getDragLayer() + .getDescendantRectRelativeToSelf(currCellLayout, mHighlightRect); + canvas.clipRect(mHighlightRect, Region.Op.DIFFERENCE); + } + + canvas.drawColor(ColorUtils.setAlphaComponent(mFullScrimColor, mAlpha)); + canvas.restore(); + } + + if (mHasHotseatScrim && !mLauncher.getDeviceProfile().isVerticalBarLayout()) { + mFinalMaskRect.set(0, height - mMaskHeight, width, height); + mBottomMaskPaint.setAlpha(Math.round(MAX_HOTSEAT_SCRIM_ALPHA * (1 - mProgress))); + canvas.drawBitmap(mBottomMask, null, mFinalMaskRect, mBottomMaskPaint); + } + } + + @Override + protected void onProgressChanged() { + mAlpha = Math.round(mMaxAlpha * mProgress); + } + + @Override + public void onViewAttachedToWindow(View view) { + mWallpaperColorInfo.addOnChangeListener(this); + onExtractedColorsChanged(mWallpaperColorInfo); + } + + @Override + public void onViewDetachedFromWindow(View view) { + mWallpaperColorInfo.removeOnChangeListener(this); + } + + @Override + public void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo) { + // for super light wallpaper it needs to be darken for contrast to workspace + // for dark wallpapers the text is white so darkening works as well + mFullScrimColor = ColorUtils.compositeColors(DARK_SCRIM_COLOR, + wallpaperColorInfo.getMainColor()); + mBottomMaskPaint.setColor(mFullScrimColor); + } + + public Bitmap createDitheredAlphaMask() { + DisplayMetrics dm = mLauncher.getResources().getDisplayMetrics(); + int width = Utilities.pxFromDp(ALPHA_MASK_WIDTH_DP, dm); + int gradientHeight = Utilities.pxFromDp(ALPHA_MASK_HEIGHT_DP, dm); + Bitmap dst = Bitmap.createBitmap(width, mMaskHeight, Bitmap.Config.ALPHA_8); + Canvas c = new Canvas(dst); + Paint paint = new Paint(Paint.DITHER_FLAG); + LinearGradient lg = new LinearGradient(0, 0, 0, gradientHeight, + new int[]{ + 0x00FFFFFF, + ColorUtils.setAlphaComponent(Color.WHITE, (int) (0xFF * 0.95)), + 0xFFFFFFFF}, + new float[]{0f, 0.8f, 1f}, + Shader.TileMode.CLAMP); + paint.setShader(lg); + c.drawRect(0, 0, width, gradientHeight, paint); + return dst; + } +} diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java index 6d584cd1b5..4f8456f254 100644 --- a/src/com/android/launcher3/states/SpringLoadedState.java +++ b/src/com/android/launcher3/states/SpringLoadedState.java @@ -36,7 +36,7 @@ public class SpringLoadedState extends LauncherState { private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE | FLAG_DISABLE_ACCESSIBILITY | FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED | - FLAG_DISABLE_PAGE_CLIPPING; + FLAG_DISABLE_PAGE_CLIPPING | FLAG_PAGE_BACKGROUNDS; // Determines how long to wait after a rotation before restoring the screen orientation to // match the sensor state. diff --git a/src/com/android/launcher3/views/AllAppsScrim.java b/src/com/android/launcher3/views/AllAppsScrim.java deleted file mode 100644 index 0ef9c8f233..0000000000 --- a/src/com/android/launcher3/views/AllAppsScrim.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.views; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.support.v4.graphics.ColorUtils; -import android.util.AttributeSet; -import android.util.Property; -import android.view.View; - -import com.android.launcher3.DeviceProfile; -import com.android.launcher3.Insettable; -import com.android.launcher3.Launcher; -import com.android.launcher3.R; -import com.android.launcher3.dynamicui.WallpaperColorInfo; -import com.android.launcher3.dynamicui.WallpaperColorInfo.OnChangeListener; -import com.android.launcher3.graphics.NinePatchDrawHelper; -import com.android.launcher3.graphics.ShadowGenerator; -import com.android.launcher3.util.Themes; - -import static com.android.launcher3.graphics.NinePatchDrawHelper.EXTENSION_PX; - -public class AllAppsScrim extends View implements OnChangeListener, Insettable { - - private static final int MAX_ALPHA = 235; - private static final int MIN_ALPHA_PORTRAIT = 100; - private static final int MIN_ALPHA_LANDSCAPE = MAX_ALPHA; - - protected final WallpaperColorInfo mWallpaperColorInfo; - private final Paint mFillPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - - private final Rect mDrawRect = new Rect(); - private final Rect mPadding = new Rect(); - private final Rect mInsets = new Rect(); - - private final float mRadius; - private final int mScrimColor; - - private int mMinAlpha; - private int mAlphaRange; - - private final float mShadowBlur; - private final Bitmap mShadowBitmap; - - private final NinePatchDrawHelper mShadowHelper = new NinePatchDrawHelper(); - - private int mFillAlpha; - - private float mDrawHeight; - private float mDrawOffsetY; - - public AllAppsScrim(Context context) { - this(context, null); - } - - public AllAppsScrim(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public AllAppsScrim(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - - mWallpaperColorInfo = WallpaperColorInfo.getInstance(context); - mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor); - mRadius = getResources().getDimension(R.dimen.all_apps_scrim_radius); - mShadowBlur = getResources().getDimension(R.dimen.all_apps_scrim_blur); - - initDefaults(); - mFillAlpha = mMinAlpha; - mShadowBitmap = generateShadowBitmap(); - - updateColors(mWallpaperColorInfo); - } - - private DeviceProfile initDefaults() { - DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile(); - mMinAlpha = grid.isVerticalBarLayout() - ? MIN_ALPHA_LANDSCAPE : MIN_ALPHA_PORTRAIT; - mAlphaRange = MAX_ALPHA - mMinAlpha; - return grid; - } - - private Bitmap generateShadowBitmap() { - float curveBot = mRadius + mShadowBlur; - - ShadowGenerator.Builder builder = new ShadowGenerator.Builder(Color.TRANSPARENT); - builder.radius = mRadius; - builder.shadowBlur = mShadowBlur; - - // Create the bitmap such that only the top half is drawn in the bitmap. - int bitmapWidth = 2 * Math.round(curveBot) + EXTENSION_PX; - int bitmapHeight = bitmapWidth / 2; - Bitmap result = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888); - - float fullSize = 2 * curveBot + EXTENSION_PX - mShadowBlur; - builder.bounds.set(mShadowBlur, mShadowBlur, fullSize, fullSize); - builder.drawShadow(new Canvas(result)); - return result; - } - - public Bitmap getShadowBitmap() { - return mShadowBitmap; - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - mWallpaperColorInfo.addOnChangeListener(this); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mWallpaperColorInfo.removeOnChangeListener(this); - } - - @Override - public void onExtractedColorsChanged(WallpaperColorInfo info) { - updateColors(info); - invalidate(); - } - - private void updateColors(WallpaperColorInfo info) { - mFillPaint.setColor(ColorUtils.compositeColors(mScrimColor, - ColorUtils.compositeColors(mScrimColor, info.getMainColor()))); - mFillPaint.setAlpha(mFillAlpha); - invalidate(); - } - - @Override - protected void onDraw(Canvas canvas) { - float edgeTop = getHeight() + mDrawOffsetY - mDrawHeight + mPadding.top; - float edgeRight = getWidth() - mPadding.right; - - if (mPadding.left > 0 || mPadding.right > 0) { - mShadowHelper.drawVerticallyStretched(mShadowBitmap, canvas, - mPadding.left - mShadowBlur, - edgeTop - mShadowBlur, - edgeRight + mShadowBlur, - getHeight()); - } else { - mShadowHelper.draw(mShadowBitmap, canvas, mPadding.left - mShadowBlur, - edgeTop - mShadowBlur, edgeRight + mShadowBlur); - } - canvas.drawRoundRect(mPadding.left, edgeTop, edgeRight, - getHeight() + mRadius, mRadius, mRadius, mFillPaint); - } - - public void setProgress(float translateY, float alpha) { - int newAlpha = Math.round(alpha * mAlphaRange + mMinAlpha); - // Negative translation means the scrim is moving up. For negative translation, we change - // draw offset as it requires redraw (since more area of the scrim needs to be shown). For - // position translation, we simply translate the scrim down as it avoids invalidate and - // hence could be optimized by the platform. - float drawOffsetY = Math.min(translateY, 0); - - if (newAlpha != mFillAlpha || drawOffsetY != mDrawOffsetY) { - invalidateDrawRect(); - - mFillAlpha = newAlpha; - mFillPaint.setAlpha(mFillAlpha); - mDrawOffsetY = drawOffsetY; - invalidateDrawRect(); - } - - setTranslationY(Math.max(translateY, 0)); - } - - private void invalidateDrawRect() { - mDrawRect.top = (int) (getHeight() - + mDrawOffsetY - mDrawHeight + mPadding.top - mShadowBlur - 0.5f); - invalidate(mDrawRect); - } - - public void setDrawRegion(float height) { - mDrawHeight = height; - } - - @Override - public void setInsets(Rect insets) { - mInsets.set(insets); - DeviceProfile grid = initDefaults(); - if (grid.isVerticalBarLayout()) { - mPadding.set(grid.workspacePadding); - mPadding.bottom = 0; - mPadding.left += mInsets.left; - mPadding.top = mInsets.top; - mPadding.right += mInsets.right; - setDrawRegion(0); - } else { - mPadding.setEmpty(); - float scrimMargin = getResources().getDimension(R.dimen.all_apps_scrim_margin); - setDrawRegion(grid.hotseatBarSizePx + insets.bottom + scrimMargin); - } - updateDrawRect(grid); - invalidate(); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - updateDrawRect(Launcher.getLauncher(getContext()).getDeviceProfile()); - } - - private void updateDrawRect(DeviceProfile grid) { - mDrawRect.bottom = getHeight(); - if (grid.isVerticalBarLayout()) { - mDrawRect.left = (int) (mPadding.left - mShadowBlur - 0.5f); - mDrawRect.right = (int) (getWidth() - mPadding.right + 0.5f); - } else { - mDrawRect.left = 0; - mDrawRect.right = getWidth(); - } - } -} diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java index b22509ce36..c51842d0d2 100644 --- a/src/com/android/launcher3/widget/BaseWidgetSheet.java +++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java @@ -31,7 +31,7 @@ import com.android.launcher3.ItemInfo; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.dragndrop.DragOptions; -import com.android.launcher3.graphics.GradientView; +import com.android.launcher3.graphics.ColorScrim; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; import com.android.launcher3.util.SystemUiController; @@ -48,10 +48,11 @@ abstract class BaseWidgetSheet extends AbstractSlideInView /* Touch handling related member variables. */ private Toast mWidgetInstructionToast; - protected GradientView mGradientView; + protected final ColorScrim mColorScrim; public BaseWidgetSheet(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); + mColorScrim = ColorScrim.createExtractedColorScrim(this); } @Override @@ -80,7 +81,7 @@ abstract class BaseWidgetSheet extends AbstractSlideInView protected void setTranslationShift(float translationShift) { super.setTranslationShift(translationShift); - mGradientView.setAlpha(1 - mTranslationShift); + mColorScrim.setProgress(1 - mTranslationShift); } private boolean beginDraggingWidget(WidgetCell v) { diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java index 6a9013d7e4..a2584852bc 100644 --- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java +++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java @@ -32,7 +32,6 @@ import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.Interpolators; -import com.android.launcher3.graphics.GradientView; import com.android.launcher3.model.WidgetItem; import com.android.launcher3.util.PackageUserKey; @@ -55,10 +54,6 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable { super(context, attrs, defStyleAttr); setWillNotDraw(false); mInsets = new Rect(); - - mGradientView = (GradientView) mLauncher.getLayoutInflater().inflate( - R.layout.widgets_bottom_sheet_scrim, mLauncher.getDragLayer(), false); - mGradientView.setProgress(1, false); mContent = this; } @@ -75,7 +70,6 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable { onWidgetsBound(); - mLauncher.getDragLayer().addView(mGradientView); mLauncher.getDragLayer().addView(this); mIsOpen = false; open(true); @@ -156,12 +150,6 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable { handleClose(animate, DEFAULT_CLOSE_DURATION); } - @Override - protected void onCloseComplete() { - super.onCloseComplete(); - mLauncher.getDragLayer().removeView(mGradientView); - } - @Override protected boolean isOfType(@FloatingViewType int type) { return (type & TYPE_WIDGETS_BOTTOM_SHEET) != 0; diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java index e461afc201..48f8afecdc 100644 --- a/src/com/android/launcher3/widget/WidgetsFullSheet.java +++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java @@ -71,9 +71,6 @@ public class WidgetsFullSheet extends BaseWidgetSheet mRecyclerView.setAdapter(mAdapter); mAdapter.setApplyBitmapDeferred(true, mRecyclerView); - mGradientView = findViewById(R.id.gradient_bg); - mGradientView.setProgress(1, false); - onWidgetsBound(); } @@ -110,12 +107,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthUsed; if (mInsets.bottom > 0) { - // If we have bottom insets, we do not show the scrim as it would overlap - // with the navbar scrim - mGradientView.setVisibility(View.INVISIBLE); widthUsed = 0; } else { - mGradientView.setVisibility(View.VISIBLE); Rect padding = mLauncher.getDeviceProfile().workspacePadding; widthUsed = Math.max(padding.left + padding.right, 2 * (mInsets.left + mInsets.right)); @@ -124,15 +117,14 @@ public class WidgetsFullSheet extends BaseWidgetSheet int heightUsed = mInsets.top + mLauncher.getDeviceProfile().edgeMarginPx; measureChildWithMargins(mContent, widthMeasureSpec, widthUsed, heightMeasureSpec, heightUsed); - measureChild(mGradientView, widthMeasureSpec, heightMeasureSpec); - setMeasuredDimension(mGradientView.getMeasuredWidth(), mGradientView.getMeasuredHeight()); + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), + MeasureSpec.getSize(heightMeasureSpec)); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int width = r - l; int height = b - t; - mGradientView.layout(0, 0, width, height); // Content is laid out as center bottom aligned int contentWidth = mContent.getMeasuredWidth(); @@ -177,13 +169,10 @@ public class WidgetsFullSheet extends BaseWidgetSheet mOpenCloseAnimator.removeListener(this); } }); - post(new Runnable() { - @Override - public void run() { - mRecyclerView.setLayoutFrozen(true); - mOpenCloseAnimator.start(); - mContent.animate().alpha(1).setDuration(FADE_IN_DURATION); - } + post(() -> { + mRecyclerView.setLayoutFrozen(true); + mOpenCloseAnimator.start(); + mContent.animate().alpha(1).setDuration(FADE_IN_DURATION); }); } else { setTranslationShift(TRANSLATION_SHIFT_OPENED); diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java index fd33ee1f40..2acd29bc69 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java @@ -33,7 +33,8 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; */ public class AllAppsState extends LauncherState { - private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY; + private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY + | FLAG_SHOW_SCRIM | FLAG_ALL_APPS_SCRIM; private static final PageAlphaProvider PAGE_ALPHA_PROVIDER = new PageAlphaProvider(DEACCEL_2) { @Override diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java index d18901d361..14806c06eb 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java @@ -37,7 +37,7 @@ public class OverviewState extends LauncherState { private static final float SCALE_FACTOR = 0.7f; private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE | - FLAG_DISABLE_PAGE_CLIPPING; + FLAG_DISABLE_PAGE_CLIPPING | FLAG_PAGE_BACKGROUNDS; public OverviewState(int id) { super(id, ContainerType.WORKSPACE, OVERVIEW_TRANSITION_MS, STATE_FLAGS); From dd535466bf2ce88e07d489fa05a9caed274b028e Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Thu, 1 Mar 2018 12:36:02 -0800 Subject: [PATCH 020/127] Don't show Pin option when an locked to app is active Also isLockToAppEnabled is renamed to isScreenPinningEnabled Bug: 72799389 Change-Id: I46d4c57e3719f7401887e79cbb7397e23f162e44 --- quickstep/libs/sysui_shared.jar | Bin 116722 -> 116779 bytes .../android/quickstep/TaskSystemShortcut.java | 6 +++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar index 0e45791a6042a11cf705d873a7209e7d64747457..d76cd25ded82b00cc39df29bb1b92e9edb809d4a 100644 GIT binary patch delta 12641 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 XuWq&Q$JHI^>M%fvu9Xju1nK_)+@c7a delta 12610 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 extends SystemShortcut if (sysUiProxy == null) { return null; } - if (!ActivityManagerWrapper.getInstance().isLockToAppEnabled()) { + if (!ActivityManagerWrapper.getInstance().isScreenPinningEnabled()) { + return null; + } + if (ActivityManagerWrapper.getInstance().isLockToAppActive()) { + // We shouldn't be able to pin while an app is locked. return null; } return view -> { From dbd6bb348c1c10e34d7488a741845648e1f7e88c Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 1 Mar 2018 14:55:22 -0800 Subject: [PATCH 021/127] Simplifying all-apps search box > Giving the search box a solid background so that it work fine with scrolling > bottom shadow logic for search box Bug: 73085356 Change-Id: Ie4dc4922be39ffd8e2d562becedbd4c6f820e6c9 --- ..._divider.xml => bg_all_apps_searchbox.xml} | 9 +-- res/layout/all_apps.xml | 2 +- res/layout/search_container_all_apps.xml | 70 +++++----------- res/values-sw720dp/styles.xml | 1 - res/values/dimens.xml | 2 +- res/values/styles.xml | 1 - .../allapps/AllAppsContainerView.java | 5 +- .../launcher3/allapps/FloatingHeaderView.java | 11 ++- .../launcher3/allapps/SearchUiManager.java | 2 +- .../search/AppsSearchContainerLayout.java | 81 ++++++++++--------- .../search/HeaderElevationController.java | 81 ------------------- .../launcher3/graphics/IconNormalizer.java | 3 + .../launcher3/uioverrides/OverviewPanel.java | 4 +- 13 files changed, 85 insertions(+), 187 deletions(-) rename res/drawable/{all_apps_search_divider.xml => bg_all_apps_searchbox.xml} (78%) delete mode 100644 src/com/android/launcher3/allapps/search/HeaderElevationController.java diff --git a/res/drawable/all_apps_search_divider.xml b/res/drawable/bg_all_apps_searchbox.xml similarity index 78% rename from res/drawable/all_apps_search_divider.xml rename to res/drawable/bg_all_apps_searchbox.xml index 99905e4233..c3249279af 100644 --- a/res/drawable/all_apps_search_divider.xml +++ b/res/drawable/bg_all_apps_searchbox.xml @@ -1,5 +1,5 @@ - - - - + + + \ No newline at end of file diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml index 2ce6b8cfd2..a7f0026a43 100644 --- a/res/layout/all_apps.xml +++ b/res/layout/all_apps.xml @@ -37,7 +37,7 @@ platform bug, which prevents using custom attributes in tag --> + layout="@layout/search_container_all_apps"/> - - - - - - - - - \ No newline at end of file + android:layout_height="@dimen/all_apps_search_bar_field_height" + android:layout_centerHorizontal="true" + android:layout_gravity="top|center_horizontal" + android:layout_marginTop="8dp" + android:background="@drawable/bg_all_apps_searchbox" + android:elevation="1dp" + android:focusableInTouchMode="true" + android:gravity="center" + android:hint="@string/all_apps_search_bar_hint" + android:imeOptions="actionSearch|flagNoExtractUi" + android:inputType="text|textNoSuggestions|textCapWords" + android:maxLines="1" + android:padding="8dp" + android:saveEnabled="false" + android:scrollHorizontally="true" + android:singleLine="true" + android:textColor="?android:attr/textColorSecondary" + android:textColorHint="@drawable/all_apps_search_hint" + android:textSize="16sp" + android:translationY="24dp" /> \ No newline at end of file diff --git a/res/values-sw720dp/styles.xml b/res/values-sw720dp/styles.xml index 72894dcf37..f322e9f31b 100644 --- a/res/values-sw720dp/styles.xml +++ b/res/values-sw720dp/styles.xml @@ -26,7 +26,6 @@ true true ?android:attr/textColorSecondary - @layout/search_container_all_apps diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 1f468445c9..9f4233c398 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -79,7 +79,7 @@ 0dp 48dp - 60dp + 30dp 40dp 144dp 700dp diff --git a/res/values/styles.xml b/res/values/styles.xml index 8cc4743a32..ac6a6b1b53 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -25,7 +25,6 @@ true true #FF757575 - @layout/search_container_all_apps