From dfb5cc9a09d5d8639fbccf76540e4182b8a0cdf9 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Mon, 26 Feb 2018 16:41:57 -0800 Subject: [PATCH 001/128] 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/128] 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/128] 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/128] 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/128] 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/128] 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/128] 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/128] 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/128] 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/128] 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/128] 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/128] 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/128] 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/128] 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/128] 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/128] 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/128] 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/128] 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/128] 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/128] 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/128] 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 diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml index 25bfc02f44..fc68b82869 100644 --- a/res/values-ta/strings.xml +++ b/res/values-ta/strings.xml @@ -137,8 +137,7 @@ "பணி" "பணி விவரம்" "பணி ஆப்ஸை இங்கு காணலாம்" - - + "ஒவ்வொரு பணிப் பயன்பாடும் ஆரஞ்சு நிற பேட்ஜைக் கொண்டிருக்கும். இவை, உங்கள் நிறுவனத்தால் பாதுகாப்பாக வைக்கப்பட்டுள்ளன. இந்த ஆப்ஸை எளிதாக அணுக, முகப்புத் திரைக்கு நகர்த்திக்கொள்ளவும்." "உங்கள் நிறுவனம் நிர்வகிக்கிறது" "ஆப்ஸும் அறிவிப்புகளும் ஆஃப் செய்யப்பட்டுள்ளன" diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml index 6af501138f..fb8a71b1e3 100644 --- a/res/values-te/strings.xml +++ b/res/values-te/strings.xml @@ -137,8 +137,7 @@ "కార్యాలయం" "కార్యాలయ ప్రొఫైల్" "కార్యాలయ యాప్‌లను ఇక్కడ కనుగొనండి" - - + "ప్రతి కార్యాలయ యాప్‌కు నారింజ బ్యాడ్జ్‌ ఉంది మరియు మీ సంస్థ ద్వారా సురక్షితంగా ఉంచబడుతుంది. సులభ యాక్సెస్ కోసం యాప్‌లను మీ హోమ్ స్క్రీన్‌కి తరలించండి." "మీ సంస్థ ద్వారా నిర్వహించబడతాయి" "నోటిఫికేషన్‌లు మరియు యాప్‌లు ఆఫ్ చేయబడ్డాయి" diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml index 866bfc913c..6f2bc710a6 100644 --- a/res/values-th/strings.xml +++ b/res/values-th/strings.xml @@ -137,8 +137,7 @@ "งาน" "โปรไฟล์งาน" "หาแอปงานที่นี่" - - + "แอปงานแต่ละแอปมีป้ายสีส้มและได้รับการรักษาความปลอดภัยจากองค์กรของคุณ ย้ายแอปไปยังหน้าจอหลักเพื่อให้เข้าถึงได้ง่ายขึ้น" "จัดการโดยองค์กร" "ปิดการแจ้งเตือนและแอปอยู่" diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml index d0a820d917..5aad29a652 100644 --- a/res/values-tl/strings.xml +++ b/res/values-tl/strings.xml @@ -137,8 +137,7 @@ "Trabaho" "Profile sa trabaho" "Maghanap ng mga app para sa trabaho rito" - - + "Ang bawat app para sa trabaho ay may orange na badge at pinapanatiling ligtas ng iyong organisasyon. Ilipat ang mga app sa iyong Home screen para mas madaling ma-access." "Pinamamahalaan ng iyong organisasyon" "Naka-off ang mga notification at app" diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index 1f75b6781e..a0ebe6f050 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -137,8 +137,7 @@ "İş" "İş profili" "İş uygulamalarını burada bulabilirsiniz" - - + "Her iş uygulamasında, uygulama güvenliğinin kuruluşunuz tarafından sağlandığını gösteren turuncu bir rozet bulunur. Uygulamaları daha kolay erişim için Ana ekranınıza taşıyın." "Kuruluşunuz tarafından yönetiliyor" "Bildirimler ve uygulamalar kapalı" diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index 095ff5ba30..ffced576bc 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -139,8 +139,7 @@ "Робочі додатки" "Робочий профіль" "Робочі додатки містяться тут" - - + "Кожний робочий додаток має оранжевий значок. Його захищає організація. Для швидкого доступу перенесіть додатки на головний екран." "Профілем керує ваша організація" "Сповіщення та додатки вимкнено" diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml index ea8a4d7e70..cd657383d9 100644 --- a/res/values-ur/strings.xml +++ b/res/values-ur/strings.xml @@ -137,8 +137,7 @@ "دفتری" "دفتری پروفائل" "یہاں دفتری ایپس تلاش کریں" - - + "ہر دفتری ایپ میں نارنجی بَیج ہوتا ہے اور اسے آپ کی تنظیم محفوظ رکھتی ہے۔ زیادہ آسان رسائی کیلئے ایپس کو اپنی ہوم اسکرین پر منتقل کریں۔" "آپ کی تنظیم کے زیر انتظام" "اطلاعات اور ایپس آف ہیں" diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml index 70dc41fa73..200c2c0a16 100644 --- a/res/values-uz/strings.xml +++ b/res/values-uz/strings.xml @@ -137,8 +137,7 @@ "Ishchi" "Ishchi profil" "Ishga oid ilovalarni shu yerdan topish mumkin" - - + "Apelsinrangli nishonga ega har bir ishga oid ilova tashkilotingiz tomonidan himoyalanadi. Ishga oid ilovalarga osonroq kirish uchun ularni bosh ekranga chiqaring." "Tashkilotingiz tomonidan boshqariladi" "Bildirishnomalar va ilovalar faol emas" diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index 1b8558f40d..a5b48922b0 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -137,8 +137,7 @@ "Cơ quan" "Hồ sơ công việc" "Tìm ứng dụng công việc tại đây" - - + "Mỗi ứng dụng công việc đều có một huy hiệu màu cam và được tổ chức của bạn bảo mật. Bạn có thể di chuyển ứng dụng đến Màn hình chính để truy cập dễ dàng hơn." "Do tổ chức của bạn quản lý" "Thông báo và ứng dụng đang tắt" diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 694125711d..71e06e7aa8 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -137,8 +137,7 @@ "工作" "工作资料" "请在此处查找工作应用" - - + "每个工作应用均有一个橙色徽标,并由贵单位负责确保其安全。请将工作应用移到主屏幕,以便轻松访问。" "由贵单位管理" "通知和应用均已关闭" diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml index 86c52465b1..7f792f8063 100644 --- a/res/values-zh-rHK/strings.xml +++ b/res/values-zh-rHK/strings.xml @@ -137,8 +137,7 @@ "商務" "工作設定檔" "請在此處尋找工作應用程式" - - + "每個工作應用程式都有橙色徽章,並由您的機構負責保持安全。您可以將工作應用程式移至主畫面,以便輕鬆存取。" "由您的機構管理" "通知和應用程式已關閉" diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 1bac58a124..b95e838119 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -137,8 +137,7 @@ "公司" "Work 設定檔" "在這裡尋找辦公應用程式" - - + "每個辦公應用程式都有橘色徽章,並由貴機構負責管理及確保其安全。請將辦公應用程式移至主螢幕以便輕鬆存取。" "由貴機構所管理" "已關閉通知和應用程式" diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml index 323144bd23..65d7d4c60d 100644 --- a/res/values-zu/strings.xml +++ b/res/values-zu/strings.xml @@ -137,8 +137,7 @@ "Umsebenzi" "Iphrofayela yomsebenzi" "Thola izinhlelo zokusebenza lapha" - - + "Uhlo lokusebenza ngalunye lomsebenzi linebheji ewolintshi futhi igcinwa iphephile inhlangano yakho. Hambisa izinhlelo zokusebenza esikrinini sakho sasekhaya ngokufinyelela okulula." "Kuphethwe inhlangano yakho" "Izaziso nezinhlelo zokusebenza kuvaliwe" diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 64ca05e3c2..1351dfa847 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -44,6 +44,7 @@ + diff --git a/res/values/config.xml b/res/values/config.xml index 3f727cf38e..065ad362ec 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -116,9 +116,6 @@ - - - 150 80 @@ -127,7 +124,7 @@ - + diff --git a/res/values/dimens.xml b/res/values/dimens.xml index f8f9c2ae99..1f468445c9 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -23,6 +23,10 @@ 24dp 1dp 8dp + 80dp + 120dp + 80dp + 25dp 8dp 8dp @@ -75,7 +79,7 @@ 0dp 48dp - 30dp + 60dp 40dp 144dp 700dp @@ -223,5 +227,5 @@ 70dp - 24dp + 48dp diff --git a/res/values/drawables.xml b/res/values/drawables.xml index 1367174b1b..fea17b1530 100644 --- a/res/values/drawables.xml +++ b/res/values/drawables.xml @@ -14,7 +14,7 @@ limitations under the License. --> - @drawable/ic_setting + @drawable/ic_info_no_shadow @drawable/ic_remove_no_shadow @drawable/ic_uninstall_no_shadow \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index b39cb04057..381830c5db 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -80,9 +80,6 @@ Apps list - Personal apps list - Work apps list - Home @@ -172,8 +169,16 @@ Home settings Disabled by your admin + + Overview + + Allow Home screen rotation + + When phone is rotated + + Current Display setting doesn\'t permit rotation Notification dots @@ -186,8 +191,6 @@ To show Notification Dots, turn on app notifications for %1$s Change settings - - Show notification dots Add icon to Home screen @@ -279,6 +282,15 @@ Move to Home screen + + Move screen to left + + + Move screen to right + + + Screen moved + Resize diff --git a/res/values/styles.xml b/res/values/styles.xml index ac6a6b1b53..8cc4743a32 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -25,6 +25,7 @@ true true #FF757575 + @layout/search_container_all_apps