From edc1453cf18b60693a7a01e1506635f9d787e89c Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Sat, 1 Feb 2025 00:23:18 -0800 Subject: [PATCH] Removing BaseDraggingActivity > Merging come methods to BaseActivtiy > Separating wallpaper theme implementation to an independent class Bug: 393703968 Flag: EXEMPT refactor Test: Presubmit Change-Id: I8cdb6d1520beff3f8226b62c5b7eafd48b2c674f --- .../uioverrides/QuickstepLauncher.java | 17 +- .../android/quickstep/RecentsActivity.java | 5 +- .../OverviewWithoutFocusInputConsumer.java | 5 +- .../quickstep/views/RecentsViewContainer.java | 5 - src/com/android/launcher3/BaseActivity.java | 77 +++++++- .../launcher3/BaseDraggingActivity.java | 171 ------------------ .../android/launcher3/DropTargetHandler.kt | 2 +- src/com/android/launcher3/Launcher.java | 16 +- src/com/android/launcher3/LauncherState.java | 2 +- .../popup/PopupContainerWithArrow.java | 3 +- .../SecondaryDisplayLauncher.java | 22 +-- .../statemanager/StatefulActivity.java | 19 +- .../launcher3/util/WallpaperThemeManager.kt | 79 ++++++++ .../launcher3/views/ActivityContext.java | 15 +- .../widget/LauncherWidgetHolder.java | 7 +- .../util/WallpaperThemeManagerTest.kt | 93 ++++++++++ 16 files changed, 294 insertions(+), 244 deletions(-) delete mode 100644 src/com/android/launcher3/BaseDraggingActivity.java create mode 100644 src/com/android/launcher3/util/WallpaperThemeManager.kt create mode 100644 tests/src/com/android/launcher3/util/WallpaperThemeManagerTest.kt diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 690dec40e6..33f7d0cd60 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -459,7 +459,7 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, protected void onItemClicked(View view) { if (!mSplitToWorkspaceController.handleSecondAppSelectionForSplit(view)) { - QuickstepLauncher.super.getItemOnClickListener().onClick(view); + super.getItemOnClickListener().onClick(view); } } @@ -731,6 +731,9 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, final boolean ret = super.initDeviceProfile(idp); mDeviceProfile.isPredictiveBackSwipe = getApplicationInfo().isOnBackInvokedCallbackEnabled(); + if (ret) { + SystemUiProxy.INSTANCE.get(this).setLauncherAppIconSize(mDeviceProfile.iconSizePx); + } return ret; } @@ -1237,6 +1240,7 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, } } + @NonNull @Override public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) { ActivityOptionsWrapper activityOptions = mAppTransitionManager.getActivityLaunchOptions( @@ -1366,12 +1370,6 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, .areDesktopTasksVisibleAndNotInOverview(); } - @Override - protected void onDeviceProfileInitiated() { - super.onDeviceProfileInitiated(); - SystemUiProxy.INSTANCE.get(this).setLauncherAppIconSize(mDeviceProfile.iconSizePx); - } - @Override public void dispatchDeviceProfileChanged() { super.dispatchDeviceProfileChanged(); @@ -1508,4 +1506,9 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, public void setCanShowAllAppsEducationView(boolean canShowAllAppsEducationView) { mCanShowAllAppsEducationView = canShowAllAppsEducationView; } + + @Override + public void returnToHomescreen() { + getStateManager().goToState(LauncherState.NORMAL); + } } diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java index 5e8ea374fd..fca67c3c4f 100644 --- a/quickstep/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/src/com/android/quickstep/RecentsActivity.java @@ -26,6 +26,7 @@ import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSI import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSITION_PRE_DELAY; import static com.android.launcher3.testing.shared.TestProtocol.LAUNCHER_ACTIVITY_STOPPED_MESSAGE; import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_ORDINAL; +import static com.android.launcher3.util.WallpaperThemeManager.setWallpaperDependentTheme; import static com.android.quickstep.OverviewComponentObserver.startHomeIntentSafely; import static com.android.quickstep.TaskUtils.taskIsATargetWithMode; import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator; @@ -247,7 +248,6 @@ public final class RecentsActivity extends StatefulActivity implem @Override public void returnToHomescreen() { - super.returnToHomescreen(); // TODO(b/137318995) This should go home, but doing so removes freeform windows } @@ -261,6 +261,7 @@ public final class RecentsActivity extends StatefulActivity implem } } + @NonNull @Override public ActivityOptionsWrapper getActivityLaunchOptions(final View v, @Nullable ItemInfo item) { if (!(v instanceof TaskView)) { @@ -371,6 +372,7 @@ public final class RecentsActivity extends StatefulActivity implem @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + setWallpaperDependentTheme(this); mStateManager = new StateManager<>(this, RecentsState.BG_LAUNCHER); @@ -431,7 +433,6 @@ public final class RecentsActivity extends StatefulActivity implem */ private void initDeviceProfile() { mDeviceProfile = createDeviceProfile(); - onDeviceProfileInitiated(); } @Override diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java index 42e8694f6a..be47df9c42 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java @@ -24,11 +24,10 @@ import android.content.Context; import android.graphics.PointF; import android.view.MotionEvent; -import com.android.launcher3.BaseActivity; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; +import com.android.launcher3.views.ActivityContext; import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.RecentsAnimationDeviceState; @@ -80,7 +79,7 @@ public class OverviewWithoutFocusInputConsumer implements InputConsumer, @Override public void onSwipeUp(boolean wasFling, PointF finalVelocity) { startHomeIntentSafely(mContext, mGestureState.getHomeIntent(), null, TAG); - BaseActivity activity = BaseDraggingActivity.fromContext(mContext); + ActivityContext activity = ActivityContext.lookupContext(mContext); int state = (mGestureState != null && mGestureState.getEndTarget() != null) ? mGestureState.getEndTarget().containerType : LAUNCHER_STATE_HOME; diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java index b1a4808224..11e7d2cc41 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java +++ b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java @@ -62,11 +62,6 @@ public interface RecentsViewContainer extends ActivityContext { */ T getOverviewPanel(); - /** - * Returns the RootView - */ - View getRootView(); - /** * Dispatches a generic motion event to the view hierarchy. * Returns the current RecentsViewContainer as context diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java index 2e7526192d..6277e41c14 100644 --- a/src/com/android/launcher3/BaseActivity.java +++ b/src/com/android/launcher3/BaseActivity.java @@ -16,6 +16,7 @@ package com.android.launcher3; +import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION; import static com.android.launcher3.util.FlagDebugUtils.appendFlag; import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange; import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK; @@ -29,17 +30,27 @@ import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; import android.util.Log; +import android.view.ActionMode; +import android.view.View; import android.window.OnBackInvokedDispatcher; import androidx.annotation.IntDef; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.logging.StatsLogManager; +import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; +import com.android.launcher3.util.ActivityOptionsWrapper; +import com.android.launcher3.util.DisplayController; +import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener; +import com.android.launcher3.util.DisplayController.Info; import com.android.launcher3.util.RunnableList; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.util.ViewCache; +import com.android.launcher3.util.WindowBounds; import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.ScrimView; @@ -52,7 +63,8 @@ import java.util.StringJoiner; /** * Launcher BaseActivity */ -public abstract class BaseActivity extends Activity implements ActivityContext { +public abstract class BaseActivity extends Activity implements ActivityContext, + DisplayInfoChangeListener { private static final String TAG = "BaseActivity"; static final boolean DEBUG = false; @@ -126,6 +138,10 @@ public abstract class BaseActivity extends Activity implements ActivityContext { public @interface ActivityFlags { } + // When starting an action mode, setting this tag will cause the action mode to be cancelled + // automatically when user interacts with the launcher. + public static final Object AUTO_CANCEL_ACTION_MODE = new Object(); + /** Returns a human-readable string for the specified {@link ActivityFlags}. */ public static String getActivityStateString(@ActivityFlags int flags) { StringJoiner result = new StringJoiner("|"); @@ -160,6 +176,8 @@ public abstract class BaseActivity extends Activity implements ActivityContext { private final RunnableList[] mEventCallbacks = {new RunnableList(), new RunnableList(), new RunnableList(), new RunnableList()}; + private ActionMode mCurrentActionMode; + @Override public ViewCache getViewCache() { return mViewCache; @@ -206,6 +224,7 @@ public abstract class BaseActivity extends Activity implements ActivityContext { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); registerBackDispatcher(); + DisplayController.INSTANCE.get(this).addChangeListener(this); } @Override @@ -253,6 +272,7 @@ public abstract class BaseActivity extends Activity implements ActivityContext { protected void onDestroy() { super.onDestroy(); mEventCallbacks[EVENT_DESTROYED].executeAllAndClear(); + DisplayController.INSTANCE.get(this).removeChangeListener(this); } @Override @@ -403,6 +423,61 @@ public abstract class BaseActivity extends Activity implements ActivityContext { writer.println(prefix + "mForceInvisible: " + mForceInvisible); } + + @Override + public void onActionModeStarted(ActionMode mode) { + super.onActionModeStarted(mode); + mCurrentActionMode = mode; + } + + @Override + public void onActionModeFinished(ActionMode mode) { + super.onActionModeFinished(mode); + mCurrentActionMode = null; + } + + protected boolean isInAutoCancelActionMode() { + return mCurrentActionMode != null && AUTO_CANCEL_ACTION_MODE == mCurrentActionMode.getTag(); + } + + @Override + public boolean finishAutoCancelActionMode() { + if (isInAutoCancelActionMode()) { + mCurrentActionMode.finish(); + return true; + } + return false; + } + + @Override + @NonNull + public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) { + ActivityOptionsWrapper wrapper = ActivityContext.super.getActivityLaunchOptions(v, item); + addEventCallback(EVENT_RESUMED, wrapper.onEndCallback::executeAllAndDestroy); + return wrapper; + } + + @Override + public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) { + ActivityOptionsWrapper wrapper = + ActivityContext.super.makeDefaultActivityOptions(splashScreenStyle); + addEventCallback(EVENT_RESUMED, wrapper.onEndCallback::executeAllAndDestroy); + return wrapper; + } + + protected WindowBounds getMultiWindowDisplaySize() { + return WindowBounds.fromWindowMetrics(getWindowManager().getCurrentWindowMetrics()); + } + + @Override + public void onDisplayInfoChanged(Context context, Info info, int flags) { + if ((flags & CHANGE_ROTATION) != 0 && mDeviceProfile.isVerticalBarLayout()) { + reapplyUi(); + } + } + + protected void reapplyUi() {} + public static T fromContext(Context context) { if (context instanceof BaseActivity) { return (T) context; diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java deleted file mode 100644 index 3b93cf4abf..0000000000 --- a/src/com/android/launcher3/BaseDraggingActivity.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * 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; - -import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION; - -import android.content.Context; -import android.content.res.Configuration; -import android.os.Bundle; -import android.view.ActionMode; -import android.view.View; - -import androidx.annotation.MainThread; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.touch.ItemClickHandler; -import com.android.launcher3.util.ActivityOptionsWrapper; -import com.android.launcher3.util.DisplayController; -import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener; -import com.android.launcher3.util.DisplayController.Info; -import com.android.launcher3.util.OnColorHintListener; -import com.android.launcher3.util.Themes; -import com.android.launcher3.util.WallpaperColorHints; -import com.android.launcher3.util.WindowBounds; - -/** - * Extension of BaseActivity allowing support for drag-n-drop - */ -@SuppressWarnings("NewApi") -public abstract class BaseDraggingActivity extends BaseActivity - implements OnColorHintListener, DisplayInfoChangeListener { - - // When starting an action mode, setting this tag will cause the action mode to be cancelled - // automatically when user interacts with the launcher. - public static final Object AUTO_CANCEL_ACTION_MODE = new Object(); - - private ActionMode mCurrentActionMode; - - private int mThemeRes = R.style.AppTheme; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - DisplayController.INSTANCE.get(this).addChangeListener(this); - - // Update theme - WallpaperColorHints.get(this).registerOnColorHintsChangedListener(this); - int themeRes = Themes.getActivityThemeRes(this); - if (themeRes != mThemeRes) { - mThemeRes = themeRes; - setTheme(themeRes); - } - } - - @MainThread - @Override - public void onColorHintsChanged(int colorHints) { - updateTheme(); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - updateTheme(); - } - - private void updateTheme() { - if (mThemeRes != Themes.getActivityThemeRes(this)) { - recreateToUpdateTheme(); - } - } - - protected void recreateToUpdateTheme() { - recreate(); - } - - @Override - public void onActionModeStarted(ActionMode mode) { - super.onActionModeStarted(mode); - mCurrentActionMode = mode; - } - - @Override - public void onActionModeFinished(ActionMode mode) { - super.onActionModeFinished(mode); - mCurrentActionMode = null; - } - - protected boolean isInAutoCancelActionMode() { - return mCurrentActionMode != null && AUTO_CANCEL_ACTION_MODE == mCurrentActionMode.getTag(); - } - - @Override - public boolean finishAutoCancelActionMode() { - if (isInAutoCancelActionMode()) { - mCurrentActionMode.finish(); - return true; - } - return false; - } - - public abstract View getRootView(); - - public void returnToHomescreen() { - // no-op - } - - @Override - @NonNull - public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) { - ActivityOptionsWrapper wrapper = super.getActivityLaunchOptions(v, item); - addEventCallback(EVENT_RESUMED, wrapper.onEndCallback::executeAllAndDestroy); - return wrapper; - } - - @Override - public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) { - ActivityOptionsWrapper wrapper = super.makeDefaultActivityOptions(splashScreenStyle); - addEventCallback(EVENT_RESUMED, wrapper.onEndCallback::executeAllAndDestroy); - return wrapper; - } - - @Override - protected void onDestroy() { - super.onDestroy(); - DisplayController.INSTANCE.get(this).removeChangeListener(this); - WallpaperColorHints.get(this).unregisterOnColorsChangedListener(this); - } - - protected void onDeviceProfileInitiated() { - } - - @Override - public void onDisplayInfoChanged(Context context, Info info, int flags) { - if ((flags & CHANGE_ROTATION) != 0 && mDeviceProfile.isVerticalBarLayout()) { - reapplyUi(); - } - } - - @Override - public View.OnClickListener getItemOnClickListener() { - return ItemClickHandler.INSTANCE; - } - - protected abstract void reapplyUi(); - - protected WindowBounds getMultiWindowDisplaySize() { - return WindowBounds.fromWindowMetrics(getWindowManager().getCurrentWindowMetrics()); - } - - @Override - public boolean isAppBlockedForSafeMode() { - return LauncherAppState.getInstance(this).isSafeModeEnabled(); - } -} diff --git a/src/com/android/launcher3/DropTargetHandler.kt b/src/com/android/launcher3/DropTargetHandler.kt index 66c948a4dd..0cc7fc7d72 100644 --- a/src/com/android/launcher3/DropTargetHandler.kt +++ b/src/com/android/launcher3/DropTargetHandler.kt @@ -2,7 +2,7 @@ package com.android.launcher3 import android.content.ComponentName import android.view.View -import com.android.launcher3.BaseDraggingActivity.EVENT_RESUMED +import com.android.launcher3.BaseActivity.EVENT_RESUMED import com.android.launcher3.DropTarget.DragObject import com.android.launcher3.LauncherConstants.ActivityCodes import com.android.launcher3.SecondaryDropTarget.DeferredOnComplete diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 647d2ad97b..a7a68d1b49 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -102,6 +102,7 @@ import static com.android.launcher3.testing.shared.TestProtocol.LAUNCHER_ACTIVIT import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.ItemInfoMatcher.forFolderMatch; import static com.android.launcher3.util.SettingsCache.TOUCHPAD_NATURAL_SCROLLING; +import static com.android.launcher3.util.WallpaperThemeManager.setWallpaperDependentTheme; import android.animation.Animator; import android.animation.AnimatorSet; @@ -144,6 +145,7 @@ import android.view.KeyboardShortcutGroup; import android.view.Menu; import android.view.MotionEvent; import android.view.View; +import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.ViewTreeObserver.OnPreDrawListener; import android.view.WindowInsets; @@ -222,6 +224,7 @@ import com.android.launcher3.states.RotationHelper; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.touch.AllAppsSwipeController; +import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.touch.ItemLongClickListener; import com.android.launcher3.util.ActivityResultInfo; import com.android.launcher3.util.BackPressHandler; @@ -509,6 +512,7 @@ public class Launcher extends StatefulActivity } super.onCreate(savedInstanceState); + setWallpaperDependentTheme(this); LauncherAppState app = LauncherAppState.getInstance(this); mModel = app.getModel(); @@ -819,7 +823,6 @@ public class Launcher extends StatefulActivity this, getMultiWindowDisplaySize()); } - onDeviceProfileInitiated(); if (FOLDABLE_SINGLE_PAGE.get() && mDeviceProfile.isTwoPanels) { mCellPosMapper = new TwoPanelCellPosMapper(mDeviceProfile.inv.numColumns); } else { @@ -2840,12 +2843,6 @@ public class Launcher extends StatefulActivity // Overridden } - @Override - public void returnToHomescreen() { - super.returnToHomescreen(); - getStateManager().goToState(LauncherState.NORMAL); - } - public void closeOpenViews() { closeOpenViews(true); } @@ -3170,5 +3167,10 @@ public class Launcher extends StatefulActivity return findViewById(R.id.popup_container); } + @Override + public OnClickListener getItemOnClickListener() { + return ItemClickHandler.INSTANCE; + } + // End of Getters and Setters } diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java index 7d5e481432..79e9bd2007 100644 --- a/src/com/android/launcher3/LauncherState.java +++ b/src/com/android/launcher3/LauncherState.java @@ -345,7 +345,7 @@ public abstract class LauncherState implements BaseState { public final float getDepth(DEVICE_PROFILE_CONTEXT context) { return getDepth(context, - BaseDraggingActivity.fromContext(context).getDeviceProfile().isMultiWindowMode); + ActivityContext.lookupContext(context).getDeviceProfile().isMultiWindowMode); } /** diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 1c9db17822..e52ca6d23d 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -40,7 +40,6 @@ import android.widget.ImageView; import androidx.annotation.LayoutRes; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.BubbleTextView; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; @@ -579,7 +578,7 @@ public class PopupContainerWithArrow /** * Dismisses the popup if it is no longer valid */ - public static void dismissInvalidPopup(BaseDraggingActivity activity) { + public static void dismissInvalidPopup(T activity) { PopupContainerWithArrow popup = getOpen(activity); if (popup != null && (!popup.mOriginalIcon.isAttachedToWindow() || !ShortcutUtil.supportsShortcuts((ItemInfo) popup.mOriginalIcon.getTag()))) { diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java index 9b3292d3ff..df27b542c2 100644 --- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java +++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java @@ -15,6 +15,8 @@ */ package com.android.launcher3.secondarydisplay; +import static com.android.launcher3.util.WallpaperThemeManager.setWallpaperDependentTheme; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.content.Intent; @@ -29,7 +31,7 @@ import android.view.inputmethod.InputMethodManager; import androidx.annotation.UiThread; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.BaseDraggingActivity; +import com.android.launcher3.BaseActivity; import com.android.launcher3.BubbleTextView; import com.android.launcher3.DragSource; import com.android.launcher3.DropTarget; @@ -59,7 +61,6 @@ import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.Themes; import com.android.launcher3.views.BaseDragLayer; -import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider; import java.util.HashMap; import java.util.Map; @@ -67,7 +68,7 @@ import java.util.Map; /** * Launcher activity for secondary displays */ -public class SecondaryDisplayLauncher extends BaseDraggingActivity +public class SecondaryDisplayLauncher extends BaseActivity implements BgDataModel.Callbacks, DragController.DragListener { private LauncherModel mModel; @@ -77,7 +78,6 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity private View mAppsButton; private PopupDataProvider mPopupDataProvider; - private WidgetPickerDataProvider mWidgetPickerDataProvider; private boolean mAppDrawerShown = false; @@ -90,6 +90,7 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + setWallpaperDependentTheme(this); mModel = LauncherAppState.getInstance(this).getModel(); mDragController = new SecondaryDragController(this); mSecondaryDisplayPredictions = SecondaryDisplayPredictions.newInstance(this); @@ -201,14 +202,6 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity return mAppsView; } - @Override - public View getRootView() { - return mDragLayer; - } - - @Override - protected void reapplyUi() { } - @Override public BaseDragLayer getDragLayer() { return mDragLayer; @@ -316,11 +309,6 @@ public class SecondaryDisplayLauncher extends BaseDraggingActivity return mPopupDataProvider; } - @Override - public WidgetPickerDataProvider getWidgetPickerDataProvider() { - return mWidgetPickerDataProvider; - } - @Override public OnClickListener getItemOnClickListener() { return this::onIconClicked; diff --git a/src/com/android/launcher3/statemanager/StatefulActivity.java b/src/com/android/launcher3/statemanager/StatefulActivity.java index f21e5da179..15190f6a18 100644 --- a/src/com/android/launcher3/statemanager/StatefulActivity.java +++ b/src/com/android/launcher3/statemanager/StatefulActivity.java @@ -18,7 +18,6 @@ package com.android.launcher3.statemanager; import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE; -import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE_RECREATE_TO_UPDATE_THEME; import static com.android.launcher3.LauncherState.FLAG_NON_INTERACTIVE; import android.content.Context; @@ -30,9 +29,8 @@ import android.view.LayoutInflater; import android.view.View; import androidx.annotation.CallSuper; -import androidx.annotation.NonNull; -import com.android.launcher3.BaseDraggingActivity; +import com.android.launcher3.BaseActivity; import com.android.launcher3.LauncherRootView; import com.android.launcher3.Utilities; import com.android.launcher3.statemanager.StateManager.StateHandler; @@ -46,7 +44,7 @@ import java.util.List; * @param Type of state object */ public abstract class StatefulActivity> - extends BaseDraggingActivity implements StatefulContainer { + extends BaseActivity implements StatefulContainer { public final Handler mHandler = new Handler(); private final Runnable mHandleDeferredResume = this::handleDeferredResume; @@ -56,7 +54,6 @@ public abstract class StatefulActivity> protected Configuration mOldConfig; private int mOldRotation; - private boolean mRecreateToUpdateTheme = false; @Override protected void onCreate(Bundle savedInstanceState) { @@ -66,18 +63,6 @@ public abstract class StatefulActivity> mOldRotation = WindowManagerProxy.INSTANCE.get(this).getRotation(this); } - @Override - protected void onSaveInstanceState(@NonNull Bundle outState) { - outState.putBoolean(RUNTIME_STATE_RECREATE_TO_UPDATE_THEME, mRecreateToUpdateTheme); - super.onSaveInstanceState(outState); - } - - @Override - protected void recreateToUpdateTheme() { - mRecreateToUpdateTheme = true; - super.recreateToUpdateTheme(); - } - /** * Create handlers to control the property changes for this activity */ diff --git a/src/com/android/launcher3/util/WallpaperThemeManager.kt b/src/com/android/launcher3/util/WallpaperThemeManager.kt new file mode 100644 index 0000000000..c48ef071ba --- /dev/null +++ b/src/com/android/launcher3/util/WallpaperThemeManager.kt @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2025 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.app.Activity +import android.content.ComponentCallbacks +import android.content.res.Configuration +import android.os.Bundle +import com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE_RECREATE_TO_UPDATE_THEME +import com.android.launcher3.R + +/** Utility class to manage activity's theme in case it is wallpaper dependent */ +class WallpaperThemeManager private constructor(private val activity: Activity) : + OnColorHintListener, ActivityLifecycleCallbacksAdapter, ComponentCallbacks { + + private var themeRes: Int = R.style.AppTheme + + private var recreateToUpdateTheme = false + + init { + // Update theme + WallpaperColorHints.get(activity).registerOnColorHintsChangedListener(this) + val expectedTheme = Themes.getActivityThemeRes(activity) + if (expectedTheme != themeRes) { + themeRes = expectedTheme + activity.setTheme(expectedTheme) + } + + activity.registerActivityLifecycleCallbacks(this) + activity.registerComponentCallbacks(this) + } + + override fun onActivitySaveInstanceState(activity: Activity, bundle: Bundle) = + bundle.putBoolean(RUNTIME_STATE_RECREATE_TO_UPDATE_THEME, recreateToUpdateTheme) + + override fun onActivityDestroyed(unused: Activity) = + WallpaperColorHints.get(activity).unregisterOnColorsChangedListener(this) + + override fun onConfigurationChanged(config: Configuration) = updateTheme() + + override fun onLowMemory() {} + + override fun onColorHintsChanged(colorHints: Int) = updateTheme() + + private fun updateTheme() { + if (themeRes != Themes.getActivityThemeRes(activity)) { + recreateToUpdateTheme = true + activity.recreate() + } + } + + companion object { + + /** + * Sets a wallpaper dependent theme on this activity. The activity is automatically + * recreated when a wallpaper change can potentially change the theme. + */ + @JvmStatic + fun Activity.setWallpaperDependentTheme() { + if (!isDestroyed) { + WallpaperThemeManager(this) + } + } + } +} diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java index b164b7ffad..c9acca7014 100644 --- a/src/com/android/launcher3/views/ActivityContext.java +++ b/src/com/android/launcher3/views/ActivityContext.java @@ -62,6 +62,7 @@ import com.android.launcher3.BubbleTextView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.DropTargetHandler; +import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; import com.android.launcher3.Utilities; @@ -166,6 +167,11 @@ public interface ActivityContext { return false; } + /** Returns the RootView */ + default View getRootView() { + return getDragLayer(); + } + /** * The root view to support drag-and-drop and popup support. */ @@ -410,7 +416,8 @@ public interface ActivityContext { View v, Intent intent, @Nullable ItemInfo item) { Preconditions.assertUIThread(); Context context = (Context) this; - if (isAppBlockedForSafeMode() && !new ApplicationInfoWrapper(context, intent).isSystem()) { + if (LauncherAppState.getInstance(context).isSafeModeEnabled() + && !new ApplicationInfoWrapper(context, intent).isSystem()) { Toast.makeText(context, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show(); return null; } @@ -456,11 +463,6 @@ public interface ActivityContext { return null; } - /** Returns {@code true} if an app launch is blocked due to safe mode. */ - default boolean isAppBlockedForSafeMode() { - return false; - } - /** * Creates and logs a new app launch event. */ @@ -476,6 +478,7 @@ public interface ActivityContext { * @param v View initiating a launch. * @param item Item associated with the view. */ + @NonNull default ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) { int left = 0, top = 0; int width = v.getMeasuredWidth(), height = v.getMeasuredHeight(); diff --git a/src/com/android/launcher3/widget/LauncherWidgetHolder.java b/src/com/android/launcher3/widget/LauncherWidgetHolder.java index f499fca165..78197e2dd0 100644 --- a/src/com/android/launcher3/widget/LauncherWidgetHolder.java +++ b/src/com/android/launcher3/widget/LauncherWidgetHolder.java @@ -41,7 +41,6 @@ import androidx.annotation.VisibleForTesting; import androidx.annotation.WorkerThread; import com.android.launcher3.BaseActivity; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.model.data.ItemInfo; @@ -50,6 +49,7 @@ import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.util.LooperExecutor; import com.android.launcher3.util.ResourceBasedOverride; import com.android.launcher3.util.SafeCloseable; +import com.android.launcher3.views.ActivityContext; import com.android.launcher3.widget.custom.CustomWidgetManager; import java.util.ArrayList; @@ -218,8 +218,7 @@ public class LauncherWidgetHolder { * @param widgetId The ID of the widget * @param requestCode The request code */ - public void startConfigActivity(@NonNull BaseDraggingActivity activity, int widgetId, - int requestCode) { + public void startConfigActivity(@NonNull BaseActivity activity, int widgetId, int requestCode) { if (!WIDGETS_ENABLED) { sendActionCancelled(activity, requestCode); return; @@ -245,7 +244,7 @@ public class LauncherWidgetHolder { * the configuration of the {@code widgetId} app widget, or null of options cannot be produced. */ @Nullable - protected Bundle getConfigurationActivityOptions(@NonNull BaseDraggingActivity activity, + protected Bundle getConfigurationActivityOptions(@NonNull ActivityContext activity, int widgetId) { LauncherAppWidgetHostView view = mViews.get(widgetId); if (view == null) { diff --git a/tests/src/com/android/launcher3/util/WallpaperThemeManagerTest.kt b/tests/src/com/android/launcher3/util/WallpaperThemeManagerTest.kt new file mode 100644 index 0000000000..4c8fd8a729 --- /dev/null +++ b/tests/src/com/android/launcher3/util/WallpaperThemeManagerTest.kt @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2025 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.app.Activity +import android.content.ComponentCallbacks +import android.content.res.Configuration +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.dx.mockito.inline.extended.ExtendedMockito.any +import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn +import com.android.dx.mockito.inline.extended.ExtendedMockito.eq +import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession +import com.android.dx.mockito.inline.extended.ExtendedMockito.times +import com.android.dx.mockito.inline.extended.ExtendedMockito.verify +import com.android.dx.mockito.inline.extended.StaticMockitoSession +import com.android.launcher3.util.WallpaperThemeManager.Companion.setWallpaperDependentTheme +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Captor +import org.mockito.Mock +import org.mockito.MockitoAnnotations +import org.mockito.kotlin.never +import org.mockito.kotlin.whenever + +/** Tests for WallpaperThemeManager */ +@SmallTest +@RunWith(AndroidJUnit4::class) +class WallpaperThemeManagerTest { + + @get:Rule val context = SandboxApplication() + + @Mock lateinit var activity: Activity + @Captor lateinit var callbacksCaptor: ArgumentCaptor + + private lateinit var mockSession: StaticMockitoSession + + @Before + fun setup() { + MockitoAnnotations.initMocks(this) + mockSession = mockitoSession().spyStatic(Themes::class.java).startMocking() + + doReturn(1).`when` { Themes.getActivityThemeRes(any()) } + doReturn(context).whenever(activity).applicationContext + } + + @After + fun tearDown() { + mockSession.finishMocking() + } + + @Test + fun `correct theme set on activity create`() { + activity.setWallpaperDependentTheme() + verify(activity, times(1)).setTheme(eq(1)) + } + + @Test + fun `ignores update if theme does not change`() { + activity.setWallpaperDependentTheme() + verify(activity).registerComponentCallbacks(callbacksCaptor.capture()) + callbacksCaptor.value.onConfigurationChanged(Configuration()) + verify(activity, never()).recreate() + } + + @Test + fun `activity recreated if theme changes`() { + activity.setWallpaperDependentTheme() + verify(activity).registerComponentCallbacks(callbacksCaptor.capture()) + + doReturn(3).`when` { Themes.getActivityThemeRes(any()) } + callbacksCaptor.value.onConfigurationChanged(Configuration()) + verify(activity, times(1)).recreate() + } +}