From dacb37c1435e68be5c96d374ba18cd58c37a19dd Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Wed, 1 Sep 2021 18:43:40 +0100 Subject: [PATCH 1/8] Only call setCurrentPage in applyLoadPlan if mCurrentPage is outdated - Apply the same for all 3 setCurrentPage cases as they can all causes page jumping Bug: 197493120 Test: manual Change-Id: I5f7013ce3ce4d6fe84c67123618c3bebeeffc43a Merged-In: I5f7013ce3ce4d6fe84c67123618c3bebeeffc43a --- .../src/com/android/quickstep/views/RecentsView.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index ce79125be1..388706071c 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -1146,20 +1146,24 @@ public abstract class RecentsView 0) { - setCurrentPage(indexOfChild(getTaskViewAt(0))); + targetPage = indexOfChild(getTaskViewAt(0)); } } else if (currentTaskId != -1) { currentTaskView = getTaskView(currentTaskId); if (currentTaskView != null) { - setCurrentPage(indexOfChild(currentTaskView)); + targetPage = indexOfChild(currentTaskView); } } + if (targetPage != -1 && mCurrentPage != targetPage) { + setCurrentPage(targetPage); + } if (mIgnoreResetTaskId != -1 && getTaskView(mIgnoreResetTaskId) != ignoreResetTaskView) { // If the taskView mapping is changing, do not preserve the visuals. Since we are From ca685ffcf79a640e2f89061f3e0e16e293479a70 Mon Sep 17 00:00:00 2001 From: y Date: Mon, 23 Aug 2021 22:44:11 -0700 Subject: [PATCH 2/8] [Search] Update AllApps header protection - Disables header protection on AOSP - Fades in/out search box pill instead of sudden movements - Work tabs protection shows and hides based on scroll position Bug: 194106968 [APK attached] Test: Manual Change-Id: I5532847ddba3d4555003b0934b8fc846dc5a5cc7 --- res/values/config.xml | 3 + .../android/launcher3/ExtendedEditText.java | 14 +++- .../allapps/AllAppsContainerView.java | 49 ++++++++----- .../launcher3/allapps/FloatingHeaderView.java | 71 +++++++++---------- 4 files changed, 78 insertions(+), 59 deletions(-) diff --git a/res/values/config.xml b/res/values/config.xml index 04c359ede3..72959b2d5c 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -34,6 +34,9 @@ popup_container_iterate_children + + false + diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java index a4e1af6fb3..21bc479c22 100644 --- a/src/com/android/launcher3/ExtendedEditText.java +++ b/src/com/android/launcher3/ExtendedEditText.java @@ -99,8 +99,18 @@ public class ExtendedEditText extends EditText { } } - // inherited class can override to change the appearance of the edit text. - public void show() {} + /** + * Sets whether EditText background should be visible + * @param maxAlpha defines the maximum alpha the background should animates to + */ + public void setBackgroundVisibility(boolean visible, float maxAlpha) {} + + /** + * Returns whether a visible background is set on EditText + */ + public boolean getBackgroundVisibility() { + return getBackground() != null; + } public void showKeyboard() { mShowImeAfterFirstLayout = !showSoftInput(); diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index f420ec2f08..5775ce6211 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -59,6 +59,7 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget.DragObject; +import com.android.launcher3.ExtendedEditText; import com.android.launcher3.Insettable; import com.android.launcher3.InsettableFrameLayout; import com.android.launcher3.R; @@ -118,7 +119,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo private SpannableStringBuilder mSearchQueryBuilder = null; protected boolean mUsingTabs; - private boolean mSearchModeWhileUsingTabs = false; + private boolean mIsSearching; protected RecyclerViewFastScroller mTouchHandler; protected final Point mFastScrollerOffset = new Point(); @@ -132,6 +133,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo private final float mHeaderThreshold; private ScrimView mScrimView; private int mHeaderColor; + private int mTabsProtectionAlpha; public AllAppsContainerView(Context context) { this(context, null); @@ -623,18 +625,19 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo for (int i = 0; i < mAH.length; i++) { mAH[i].adapter.setLastSearchQuery(query); } + mIsSearching = true; if (mUsingTabs) { - mSearchModeWhileUsingTabs = true; rebindAdapters(false); // hide tabs } mHeader.setCollapsed(true); } public void onClearSearchResult() { - if (mSearchModeWhileUsingTabs) { + if (mUsingTabs) { rebindAdapters(true); // show tabs - mSearchModeWhileUsingTabs = false; } + mIsSearching = false; + getActiveRecyclerView().scrollToTop(); } public void onSearchResultsChanged() { @@ -708,13 +711,12 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo mHeaderPaint.setColor(mHeaderColor); mHeaderPaint.setAlpha((int) (getAlpha() * Color.alpha(mHeaderColor))); if (mHeaderPaint.getColor() != mScrimColor && mHeaderPaint.getColor() != 0) { - int bottom = mUsingTabs && mHeader.mHeaderCollapsed ? mHeader.getVisibleBottomBound() - : mSearchContainer.getBottom(); - canvas.drawRect(0, 0, canvas.getWidth(), bottom + getTranslationY(), - mHeaderPaint); - - if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && getTranslationY() == 0) { - mSearchUiManager.getEditText().setBackground(null); + int bottom = (int) (mSearchContainer.getBottom() + getTranslationY()); + canvas.drawRect(0, 0, canvas.getWidth(), bottom, mHeaderPaint); + int tabsHeight = getFloatingHeaderView().getPeripheralProtectionHeight(); + if (mTabsProtectionAlpha > 0 && tabsHeight != 0) { + mHeaderPaint.setAlpha((int) (getAlpha() * mTabsProtectionAlpha)); + canvas.drawRect(0, bottom, canvas.getWidth(), bottom + tabsHeight, mHeaderPaint); } } } @@ -794,18 +796,29 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo protected void updateHeaderScroll(int scrolledOffset) { - float prog = Math.max(0, Math.min(1, (float) scrolledOffset / mHeaderThreshold)); + + float prog = Utilities.boundToRange((float) scrolledOffset / mHeaderThreshold, 0f, 1f); int viewBG = ColorUtils.blendARGB(mScrimColor, mHeaderProtectionColor, prog); int headerColor = ColorUtils.setAlphaComponent(viewBG, (int) (getSearchView().getAlpha() * 255)); - if (headerColor != mHeaderColor) { + int tabsAlpha = mHeader.getPeripheralProtectionHeight() == 0 ? 0 + : (int) (Utilities.boundToRange( + (scrolledOffset + mHeader.mSnappedScrolledY) / mHeaderThreshold, 0f, 1f) + * 255); + if (headerColor != mHeaderColor || mTabsProtectionAlpha != tabsAlpha) { mHeaderColor = headerColor; - getSearchView().setBackgroundColor(viewBG); - getFloatingHeaderView().setHeaderColor(viewBG); + mTabsProtectionAlpha = tabsAlpha; invalidateHeader(); - if (scrolledOffset == 0 && mSearchUiManager.getEditText() != null) { - mSearchUiManager.getEditText().show(); + } + if (mSearchUiManager.getEditText() != null) { + ExtendedEditText editText = mSearchUiManager.getEditText(); + boolean bgVisible = editText.getBackgroundVisibility(); + if (scrolledOffset == 0 && !mIsSearching) { + bgVisible = true; + } else if (scrolledOffset > mHeaderThreshold) { + bgVisible = false; } + editText.setBackgroundVisibility(bgVisible, 1 - prog); } } @@ -813,7 +826,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo * redraws header protection */ public void invalidateHeader() { - if (mScrimView != null && FeatureFlags.ENABLE_DEVICE_SEARCH.get()) { + if (mScrimView != null && mHeader.isHeaderProtectionSupported()) { mScrimView.invalidate(); } } diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java index 8ea83d56ac..debb5b20c1 100644 --- a/src/com/android/launcher3/allapps/FloatingHeaderView.java +++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java @@ -17,9 +17,6 @@ package com.android.launcher3.allapps; import android.animation.ValueAnimator; import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.util.ArrayMap; @@ -50,11 +47,10 @@ public class FloatingHeaderView extends LinearLayout implements ValueAnimator.AnimatorUpdateListener, PluginListener, Insettable, OnHeightUpdatedListener { - private final Rect mClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE); + private final Rect mRVClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE); + private final Rect mHeaderClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE); private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0); - private final ValueAnimator mHeaderAnimator = ValueAnimator.ofInt(0, 1).setDuration(100); private final Point mTempOffset = new Point(); - private final Paint mBGPaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() { @Override @@ -82,19 +78,19 @@ public class FloatingHeaderView extends LinearLayout implements } }; - private final int mHeaderTopPadding; - protected final Map mPluginRows = new ArrayMap<>(); + private final int mHeaderTopPadding; + private final boolean mHeaderProtectionSupported; + protected ViewGroup mTabLayout; private AllAppsRecyclerView mMainRV; private AllAppsRecyclerView mWorkRV; private AllAppsRecyclerView mCurrentRV; private ViewGroup mParent; public boolean mHeaderCollapsed; - private int mSnappedScrolledY; + protected int mSnappedScrolledY; private int mTranslationY; - private int mHeaderColor; private boolean mForwardToRecyclerView; @@ -120,6 +116,8 @@ public class FloatingHeaderView extends LinearLayout implements super(context, attrs); mHeaderTopPadding = context.getResources() .getDimensionPixelSize(R.dimen.all_apps_header_top_padding); + mHeaderProtectionSupported = context.getResources().getBoolean( + R.bool.config_header_protection_supported); } @Override @@ -138,7 +136,6 @@ public class FloatingHeaderView extends LinearLayout implements } mFixedRows = rows.toArray(new FloatingHeaderRow[rows.size()]); mAllRows = mFixedRows; - mHeaderAnimator.addUpdateListener(valueAnimator -> invalidate()); } @Override @@ -285,7 +282,7 @@ public class FloatingHeaderView extends LinearLayout implements mHeaderCollapsed = false; } mTranslationY = currentScrollY; - } else if (!mHeaderCollapsed) { + } else { mTranslationY = currentScrollY - mSnappedScrolledY - mMaxTranslation; // update state vars @@ -295,31 +292,10 @@ public class FloatingHeaderView extends LinearLayout implements } else if (mTranslationY <= -mMaxTranslation) { // hide or stay hidden mHeaderCollapsed = true; mSnappedScrolledY = -mMaxTranslation; - mHeaderAnimator.setCurrentFraction(0); - mHeaderAnimator.start(); } } } - /** - * Set current header protection background color - */ - public void setHeaderColor(int color) { - mHeaderColor = color; - invalidate(); - } - - @Override - protected void dispatchDraw(Canvas canvas) { - if (mHeaderCollapsed && !mCollapsed && mTabLayout.getVisibility() == VISIBLE - && mHeaderColor != Color.TRANSPARENT && FeatureFlags.ENABLE_DEVICE_SEARCH.get()) { - mBGPaint.setColor(mHeaderColor); - mBGPaint.setAlpha((int) (255 * mHeaderAnimator.getAnimatedFraction())); - canvas.drawRect(0, 0, getWidth(), getHeight() + mTranslationY, mBGPaint); - } - super.dispatchDraw(canvas); - } - protected void applyVerticalMove() { int uncappedTranslationY = mTranslationY; mTranslationY = Math.max(mTranslationY, -mMaxTranslation); @@ -336,11 +312,15 @@ public class FloatingHeaderView extends LinearLayout implements } mTabLayout.setTranslationY(mTranslationY); - mClip.top = mMaxTranslation + mTranslationY; + + int clipHeight = mHeaderTopPadding - getPaddingBottom(); + mRVClip.top = mTabsHidden ? clipHeight : 0; + mHeaderClip.top = clipHeight; // clipping on a draw might cause additional redraw - mMainRV.setClipBounds(mClip); + setClipBounds(mHeaderClip); + mMainRV.setClipBounds(mRVClip); if (mWorkRV != null) { - mWorkRV.setClipBounds(mClip); + mWorkRV.setClipBounds(mRVClip); } } @@ -421,6 +401,10 @@ public class FloatingHeaderView extends LinearLayout implements return false; } + public boolean isHeaderProtectionSupported() { + return mHeaderProtectionSupported; + } + @Override public boolean hasOverlappingRendering() { return false; @@ -444,10 +428,19 @@ public class FloatingHeaderView extends LinearLayout implements } /** - * Returns visible height of FloatingHeaderView contents + * Returns visible height of FloatingHeaderView contents requiring header protection */ - public int getVisibleBottomBound() { - return getBottom() + mTranslationY; + public int getPeripheralProtectionHeight() { + if (!mHeaderProtectionSupported) { + return 0; + } + + // we only want to show protection when work tab is available and header is either + // collapsed or animating to/from collapsed state + if (mTabsHidden || !mHeaderCollapsed) { + return 0; + } + return Math.max(getHeight() - getPaddingTop() + mTranslationY, 0); } } From ac6884205979d1339f5f15b8e4822a5dcfa9419a Mon Sep 17 00:00:00 2001 From: y Date: Wed, 1 Sep 2021 16:59:20 -0700 Subject: [PATCH 3/8] Remove HotseatEduActivity from AOSP Bug: 191882450 Test: manual Change-Id: Ic60ef6fec6c3d8162cb3d11b0ed3c9f89f6b5704 --- quickstep/AndroidManifest.xml | 20 ------- .../hybridhotseat/HotseatEduActivity.java | 60 ------------------- 2 files changed, 80 deletions(-) delete mode 100644 quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml index b43d8d1a4b..dc92731e16 100644 --- a/quickstep/AndroidManifest.xml +++ b/quickstep/AndroidManifest.xml @@ -22,11 +22,6 @@ xmlns:tools="http://schemas.android.com/tools" package="com.android.launcher3"> - - @@ -41,7 +36,6 @@ - - - - - - - - diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java deleted file mode 100644 index 3a7d821ed6..0000000000 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatEduActivity.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2020 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.hybridhotseat; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; - -import com.android.launcher3.BaseActivity; -import com.android.launcher3.Launcher; -import com.android.launcher3.uioverrides.QuickstepLauncher; -import com.android.launcher3.util.ActivityTracker; - -/** - * Proxy activity to return user to home screen and show halfsheet education - */ -public class HotseatEduActivity extends Activity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Intent homeIntent = new Intent(Intent.ACTION_MAIN) - .addCategory(Intent.CATEGORY_HOME) - .setPackage(getPackageName()) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - Launcher.ACTIVITY_TRACKER.registerCallback(new HotseatActivityTracker()); - startActivity(homeIntent); - finish(); - } - - static class HotseatActivityTracker implements - ActivityTracker.SchedulerCallback { - - @Override - public boolean init(BaseActivity activity, boolean alreadyOnHome) { - QuickstepLauncher launcher = (QuickstepLauncher) activity; - if (launcher != null) { - launcher.getHotseatPredictionController().showEdu(); - } - return false; - } - - } -} From 1aff018e1737da91392ec7c553755cacec734bcc Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 7 Sep 2021 12:04:16 -0400 Subject: [PATCH 4/8] Cleaning up fixed bug Bug: 192010616 Test: Presubmit Change-Id: I12d79726852a588cb0ee6b1aaf5ab8bccb9c3cfc --- .../src/com/android/launcher3/ui/widget/RequestPinItemTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java index a5694fc43d..ccbb662055 100644 --- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java +++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java @@ -42,7 +42,6 @@ import com.android.launcher3.ui.AbstractLauncherUiTest; import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator; import com.android.launcher3.util.Wait; import com.android.launcher3.util.Wait.Condition; -import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord; import com.android.launcher3.util.rule.ShellCommandRule; import org.junit.Before; @@ -78,7 +77,6 @@ public class RequestPinItemTest extends AbstractLauncherUiTest { public void testEmpty() throws Throwable { /* needed while the broken tests are being fixed */ } @Test - @ScreenRecord //b/192010616 public void testPinWidgetNoConfig() throws Throwable { runTest("pinWidgetNoConfig", true, (info, view) -> info instanceof LauncherAppWidgetInfo && ((LauncherAppWidgetInfo) info).appWidgetId == mAppWidgetId && From a8da6905a919a7cb61c965d83b8e9504ef04805d Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Tue, 7 Sep 2021 18:42:39 +0100 Subject: [PATCH 5/8] Always reset focusedTask to -1 on reset - Keep old focused task causes old focused task to be restored after applyLoadPlan: http://cs/android/packages/apps/Launcher3/quickstep/src/com/android/quickstep/views/RecentsView.java?l=1365 - This caused the nth task to be focused rather than the first task - The fix is to reset focusedTask in reset when exiting overview, focused task will be set properly next time through applyLoadPlan when overview is relaunched Fix: 199150523 Fix: 198420226 Test: TaplTestsNexus.testOverviewActions Test: Quick switch > launch app > swipe home > swipe up to overview > snap to focused task Test: split screen > swipe home > swipe up to overview > snap to focused task Change-Id: I06399626ed3ee033345bd67296d79d59a98a507f --- quickstep/src/com/android/quickstep/views/RecentsView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 3b962d8bec..b690982efb 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -1866,7 +1866,7 @@ public abstract class RecentsView 0 ? getTaskViewAt(0).getTaskViewId() : -1; + mFocusedTaskViewId = -1; if (mRecentsAnimationController != null) { if (ENABLE_QUICKSTEP_LIVE_TILE.get() && mEnableDrawingLiveTile) { From 302eff9c84cd8d9e2b41e69d3feeff3925936d3d Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Tue, 7 Sep 2021 12:03:07 -0700 Subject: [PATCH 6/8] Fix wallpaper picker crash if folder is in hotseat Only use mWorkspaceScreens if info.container == CONTAINER_DESKTOP, otherwise assume it's in mHotseat instead. Test: have a folder in hotseat, open wallpaper picker and can see the preview and set wallpaper Fixes: 199179718 Change-Id: I6f1dbd8dc387783bb8b76e2bc469508c079a85f8 --- .../android/launcher3/graphics/LauncherPreviewRenderer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java index 43ac8f98d1..7a8b5d8687 100644 --- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java +++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java @@ -324,7 +324,9 @@ public class LauncherPreviewRenderer extends ContextWrapper } private void inflateAndAddFolder(FolderInfo info) { - CellLayout screen = mWorkspaceScreens.get(info.screenId); + CellLayout screen = info.container == Favorites.CONTAINER_DESKTOP + ? mWorkspaceScreens.get(info.screenId) + : mHotseat; FolderIcon folderIcon = FolderIcon.inflateIcon(R.layout.folder_icon, this, screen, info); addInScreenFromBind(folderIcon, info); From b45aef3f1cced105d3281da04cf6ed9830482114 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 7 Sep 2021 15:33:27 -0400 Subject: [PATCH 7/8] Fixing leak in model tests > InstallSessionTracker is not released immediately causing large memory objects being held by tests Bug: 198719724 Test: Presubmit Change-Id: I1d19a2a498a9f255077818dc7d78422367ec1749 --- .../launcher3/pm/InstallSessionHelper.java | 20 +--- .../launcher3/pm/InstallSessionTracker.java | 92 ++++++++++++++----- .../launcher3/util/LauncherModelHelper.java | 7 -- 3 files changed, 71 insertions(+), 48 deletions(-) diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java index ab35bd6175..4b86f65039 100644 --- a/src/com/android/launcher3/pm/InstallSessionHelper.java +++ b/src/com/android/launcher3/pm/InstallSessionHelper.java @@ -17,7 +17,6 @@ package com.android.launcher3.pm; import static com.android.launcher3.Utilities.getPrefs; -import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -25,7 +24,6 @@ import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageManager; -import android.os.Build; import android.os.Process; import android.os.UserHandle; import android.text.TextUtils; @@ -238,24 +236,12 @@ public class InstallSessionHelper { } public InstallSessionTracker registerInstallTracker(InstallSessionTracker.Callback callback) { - InstallSessionTracker tracker = new InstallSessionTracker(this, callback); - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - mInstaller.registerSessionCallback(tracker, MODEL_EXECUTOR.getHandler()); - } else { - mLauncherApps.registerPackageInstallerSessionCallback(MODEL_EXECUTOR, tracker); - } + InstallSessionTracker tracker = new InstallSessionTracker( + this, callback, mInstaller, mLauncherApps); + tracker.register(); return tracker; } - void unregister(InstallSessionTracker tracker) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - mInstaller.unregisterSessionCallback(tracker); - } else { - mLauncherApps.unregisterPackageInstallerSessionCallback(tracker); - } - } - public static UserHandle getUserHandle(SessionInfo info) { return Utilities.ATLEAST_Q ? info.getUser() : Process.myUserHandle(); } diff --git a/src/com/android/launcher3/pm/InstallSessionTracker.java b/src/com/android/launcher3/pm/InstallSessionTracker.java index b0b907ab19..e1b3c1ae36 100644 --- a/src/com/android/launcher3/pm/InstallSessionTracker.java +++ b/src/com/android/launcher3/pm/InstallSessionTracker.java @@ -18,9 +18,12 @@ package com.android.launcher3.pm; import static com.android.launcher3.pm.InstallSessionHelper.getUserHandle; import static com.android.launcher3.pm.PackageInstallInfo.STATUS_FAILED; import static com.android.launcher3.pm.PackageInstallInfo.STATUS_INSTALLED; +import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; +import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; +import android.os.Build; import android.os.UserHandle; import android.util.SparseArray; @@ -28,35 +31,53 @@ import androidx.annotation.WorkerThread; import com.android.launcher3.util.PackageUserKey; +import java.lang.ref.WeakReference; + @WorkerThread public class InstallSessionTracker extends PackageInstaller.SessionCallback { // Lazily initialized private SparseArray mActiveSessions = null; - private final InstallSessionHelper mInstallerCompat; - private final Callback mCallback; + private final WeakReference mWeakHelper; + private final WeakReference mWeakCallback; + private final PackageInstaller mInstaller; + private final LauncherApps mLauncherApps; - InstallSessionTracker(InstallSessionHelper installerCompat, Callback callback) { - mInstallerCompat = installerCompat; - mCallback = callback; + + InstallSessionTracker(InstallSessionHelper installerCompat, Callback callback, + PackageInstaller installer, LauncherApps launcherApps) { + mWeakHelper = new WeakReference<>(installerCompat); + mWeakCallback = new WeakReference<>(callback); + mInstaller = installer; + mLauncherApps = launcherApps; } @Override public void onCreated(int sessionId) { - SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId); + InstallSessionHelper helper = mWeakHelper.get(); + Callback callback = mWeakCallback.get(); + if (callback == null || helper == null) { + return; + } + SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId, helper, callback); if (sessionInfo != null) { - mCallback.onInstallSessionCreated(PackageInstallInfo.fromInstallingState(sessionInfo)); + callback.onInstallSessionCreated(PackageInstallInfo.fromInstallingState(sessionInfo)); } - mInstallerCompat.tryQueuePromiseAppIcon(sessionInfo); + helper.tryQueuePromiseAppIcon(sessionInfo); } @Override public void onFinished(int sessionId, boolean success) { + InstallSessionHelper helper = mWeakHelper.get(); + Callback callback = mWeakCallback.get(); + if (callback == null || helper == null) { + return; + } // For a finished session, we can't get the session info. So use the // packageName from our local cache. - SparseArray activeSessions = getActiveSessionMap(); + SparseArray activeSessions = getActiveSessionMap(helper); PackageUserKey key = activeSessions.get(sessionId); activeSessions.remove(sessionId); @@ -65,21 +86,26 @@ public class InstallSessionTracker extends PackageInstaller.SessionCallback { PackageInstallInfo info = PackageInstallInfo.fromState( success ? STATUS_INSTALLED : STATUS_FAILED, packageName, key.mUser); - mCallback.onPackageStateChanged(info); + callback.onPackageStateChanged(info); - if (!success && mInstallerCompat.promiseIconAddedForId(sessionId)) { - mCallback.onSessionFailure(packageName, key.mUser); + if (!success && helper.promiseIconAddedForId(sessionId)) { + callback.onSessionFailure(packageName, key.mUser); // If it is successful, the id is removed in the the package added flow. - mInstallerCompat.removePromiseIconId(sessionId); + helper.removePromiseIconId(sessionId); } } } @Override public void onProgressChanged(int sessionId, float progress) { - SessionInfo session = mInstallerCompat.getVerifiedSessionInfo(sessionId); + InstallSessionHelper helper = mWeakHelper.get(); + Callback callback = mWeakCallback.get(); + if (callback == null || helper == null) { + return; + } + SessionInfo session = helper.getVerifiedSessionInfo(sessionId); if (session != null && session.getAppPackageName() != null) { - mCallback.onPackageStateChanged(PackageInstallInfo.fromInstallingState(session)); + callback.onPackageStateChanged(PackageInstallInfo.fromInstallingState(session)); } } @@ -88,35 +114,53 @@ public class InstallSessionTracker extends PackageInstaller.SessionCallback { @Override public void onBadgingChanged(int sessionId) { - SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId); + InstallSessionHelper helper = mWeakHelper.get(); + Callback callback = mWeakCallback.get(); + if (callback == null || helper == null) { + return; + } + SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId, helper, callback); if (sessionInfo != null) { - mInstallerCompat.tryQueuePromiseAppIcon(sessionInfo); + helper.tryQueuePromiseAppIcon(sessionInfo); } } - private SessionInfo pushSessionDisplayToLauncher(int sessionId) { - SessionInfo session = mInstallerCompat.getVerifiedSessionInfo(sessionId); + private SessionInfo pushSessionDisplayToLauncher( + int sessionId, InstallSessionHelper helper, Callback callback) { + SessionInfo session = helper.getVerifiedSessionInfo(sessionId); if (session != null && session.getAppPackageName() != null) { PackageUserKey key = new PackageUserKey(session.getAppPackageName(), getUserHandle(session)); - getActiveSessionMap().put(session.getSessionId(), key); - mCallback.onUpdateSessionDisplay(key, session); + getActiveSessionMap(helper).put(session.getSessionId(), key); + callback.onUpdateSessionDisplay(key, session); return session; } return null; } - private SparseArray getActiveSessionMap() { + private SparseArray getActiveSessionMap(InstallSessionHelper helper) { if (mActiveSessions == null) { mActiveSessions = new SparseArray<>(); - mInstallerCompat.getActiveSessions().forEach( + helper.getActiveSessions().forEach( (key, si) -> mActiveSessions.put(si.getSessionId(), key)); } return mActiveSessions; } + void register() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + mInstaller.registerSessionCallback(this, MODEL_EXECUTOR.getHandler()); + } else { + mLauncherApps.registerPackageInstallerSessionCallback(MODEL_EXECUTOR, this); + } + } + public void unregister() { - mInstallerCompat.unregister(this); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + mInstaller.unregisterSessionCallback(this); + } else { + mLauncherApps.unregisterPackageInstallerSessionCallback(this); + } } public interface Callback { diff --git a/tests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/src/com/android/launcher3/util/LauncherModelHelper.java index c9b63aeb11..59966eee04 100644 --- a/tests/src/com/android/launcher3/util/LauncherModelHelper.java +++ b/tests/src/com/android/launcher3/util/LauncherModelHelper.java @@ -66,7 +66,6 @@ import com.android.launcher3.pm.InstallSessionHelper; import com.android.launcher3.pm.UserCache; import com.android.launcher3.testing.TestInformationProvider; import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper; -import com.android.launcher3.util.MainThreadInitializedObject.ObjectProvider; import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext; import com.android.launcher3.widget.custom.CustomWidgetManager; @@ -533,12 +532,6 @@ public class LauncherModelHelper { super.onDestroy(); } - - @Override - protected T createObject(ObjectProvider provider) { - return spy(provider.get(this)); - } - @Override public PackageManager getPackageManager() { return mPm; From bfac46a30c659d3033070e680d6e1b3a4eef359f Mon Sep 17 00:00:00 2001 From: Jerry Chang Date: Wed, 8 Sep 2021 08:20:58 +0800 Subject: [PATCH 8/8] Prevent NPE when init device profile Fix: 198871283 Test: manual Change-Id: Ie303ff4f3dc05f419e80038e41e195dc874ba40a --- src/com/android/launcher3/Launcher.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 94dbe00401..bb6e1cb90d 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -600,9 +600,11 @@ public class Launcher extends StatefulActivity implements Launche private void initDeviceProfile(InvariantDeviceProfile idp) { // Load configuration-specific DeviceProfile - mDeviceProfile = isInMultiWindowMode() - ? mDeviceProfile.getMultiWindowProfile(this, getMultiWindowDisplaySize()) - : idp.getDeviceProfile(this); + mDeviceProfile = idp.getDeviceProfile(this); + if (isInMultiWindowMode()) { + mDeviceProfile = mDeviceProfile.getMultiWindowProfile( + this, getMultiWindowDisplaySize()); + } onDeviceProfileInitiated(); mModelWriter = mModel.getWriter(getDeviceProfile().isVerticalBarLayout(), true, this);