Snap for 12616459 from adfd002972 to 25Q1-release
Change-Id: Ib8c90391dd1fc473562f8a67ad1def1b614c9da1
This commit is contained in:
@@ -310,6 +310,13 @@ flag {
|
||||
bug: "346408388"
|
||||
}
|
||||
|
||||
flag {
|
||||
name: "all_apps_sheet_for_handheld"
|
||||
namespace: "launcher"
|
||||
description: "All Apps will be presented on a bottom sheet in handheld mode"
|
||||
bug: "374186088"
|
||||
}
|
||||
|
||||
flag {
|
||||
name: "multiline_search_bar"
|
||||
namespace: "launcher"
|
||||
@@ -506,3 +513,10 @@ flag {
|
||||
description: "Enable launcher app contrast tiles."
|
||||
bug: "341217082"
|
||||
}
|
||||
|
||||
flag {
|
||||
name: "msdl_feedback"
|
||||
namespace: "launcher"
|
||||
description: "Enable MSDL feedback for Launcher interactions"
|
||||
bug: "377496684"
|
||||
}
|
||||
@@ -26,6 +26,4 @@
|
||||
|
||||
<!-- Turn on work apps button -->
|
||||
<color name="work_turn_on_stroke">?attr/materialColorPrimary</color>
|
||||
<color name="work_fab_bg_color">?attr/materialColorPrimaryFixedDim</color>
|
||||
<color name="work_fab_icon_color">?attr/materialColorOnPrimaryFixed</color>
|
||||
</resources>
|
||||
@@ -94,6 +94,4 @@
|
||||
|
||||
<!-- Turn on work apps button -->
|
||||
<color name="work_turn_on_stroke">?attr/materialColorPrimary</color>
|
||||
<color name="work_fab_bg_color">?attr/materialColorPrimaryFixedDim</color>
|
||||
<color name="work_fab_icon_color">?attr/materialColorOnPrimaryFixed</color>
|
||||
</resources>
|
||||
@@ -34,7 +34,6 @@
|
||||
<string name="taskbar_view_callbacks_factory_class" translatable="false">com.android.launcher3.taskbar.TaskbarViewCallbacksFactory</string>
|
||||
<string name="launcher_restore_event_logger_class" translatable="false">com.android.quickstep.LauncherRestoreEventLoggerImpl</string>
|
||||
<string name="taskbar_edu_tooltip_controller_class" translatable="false">com.android.launcher3.taskbar.TaskbarEduTooltipController</string>
|
||||
<string name="contextual_edu_manager_class" translatable="false">com.android.quickstep.contextualeducation.SystemContextualEduStatsManager</string>
|
||||
<string name="nav_handle_long_press_handler_class" translatable="false"></string>
|
||||
<string name="contextual_search_invoker_class" translatable="false"></string>
|
||||
<string name="contextual_search_state_manager_class" translatable="false"></string>
|
||||
|
||||
@@ -560,25 +560,25 @@ public class TaskbarManager {
|
||||
}
|
||||
}
|
||||
|
||||
public void checkNavBarModes() {
|
||||
public void checkNavBarModes(int displayId) {
|
||||
if (mTaskbarActivityContext != null) {
|
||||
mTaskbarActivityContext.checkNavBarModes();
|
||||
}
|
||||
}
|
||||
|
||||
public void finishBarAnimations() {
|
||||
public void finishBarAnimations(int displayId) {
|
||||
if (mTaskbarActivityContext != null) {
|
||||
mTaskbarActivityContext.finishBarAnimations();
|
||||
}
|
||||
}
|
||||
|
||||
public void touchAutoDim(boolean reset) {
|
||||
public void touchAutoDim(int displayId, boolean reset) {
|
||||
if (mTaskbarActivityContext != null) {
|
||||
mTaskbarActivityContext.touchAutoDim(reset);
|
||||
}
|
||||
}
|
||||
|
||||
public void transitionTo(@BarTransitions.TransitionMode int barMode,
|
||||
public void transitionTo(int displayId, @BarTransitions.TransitionMode int barMode,
|
||||
boolean animate) {
|
||||
if (mTaskbarActivityContext != null) {
|
||||
mTaskbarActivityContext.transitionTo(barMode, animate);
|
||||
|
||||
@@ -118,7 +118,7 @@ public class AllAppsState extends LauncherState {
|
||||
|
||||
@Override
|
||||
public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
|
||||
if (launcher.getDeviceProfile().isTablet) {
|
||||
if (launcher.getDeviceProfile().shouldShowAllAppsOnSheet()) {
|
||||
return getWorkspaceScaleAndTranslation(launcher);
|
||||
} else {
|
||||
ScaleAndTranslation overviewScaleAndTranslation = LauncherState.OVERVIEW
|
||||
@@ -133,7 +133,7 @@ public class AllAppsState extends LauncherState {
|
||||
@Override
|
||||
protected <DEVICE_PROFILE_CONTEXT extends Context & ActivityContext>
|
||||
float getDepthUnchecked(DEVICE_PROFILE_CONTEXT context) {
|
||||
if (context.getDeviceProfile().isTablet) {
|
||||
if (context.getDeviceProfile().shouldShowAllAppsOnSheet()) {
|
||||
return context.getDeviceProfile().bottomSheetDepth;
|
||||
} else {
|
||||
// The scrim fades in at approximately 50% of the swipe gesture.
|
||||
@@ -154,7 +154,7 @@ public class AllAppsState extends LauncherState {
|
||||
return new PageAlphaProvider(DECELERATE_2) {
|
||||
@Override
|
||||
public float getPageAlpha(int pageIndex) {
|
||||
return launcher.getDeviceProfile().isTablet
|
||||
return launcher.getDeviceProfile().shouldShowAllAppsOnSheet()
|
||||
? superPageAlphaProvider.getPageAlpha(pageIndex)
|
||||
: 0;
|
||||
}
|
||||
@@ -164,8 +164,8 @@ public class AllAppsState extends LauncherState {
|
||||
@Override
|
||||
public int getVisibleElements(Launcher launcher) {
|
||||
int elements = ALL_APPS_CONTENT | FLOATING_SEARCH_BAR;
|
||||
// Only add HOTSEAT_ICONS for tablets in ALL_APPS state.
|
||||
if (launcher.getDeviceProfile().isTablet) {
|
||||
// When All Apps is presented on a bottom sheet, HOTSEAT_ICONS are visible.
|
||||
if (launcher.getDeviceProfile().shouldShowAllAppsOnSheet()) {
|
||||
elements |= HOTSEAT_ICONS;
|
||||
}
|
||||
return elements;
|
||||
@@ -202,7 +202,7 @@ public class AllAppsState extends LauncherState {
|
||||
|
||||
@Override
|
||||
public int getWorkspaceScrimColor(Launcher launcher) {
|
||||
return launcher.getDeviceProfile().isTablet
|
||||
return launcher.getDeviceProfile().shouldShowAllAppsOnSheet()
|
||||
? launcher.getResources().getColor(R.color.widgets_picker_scrim)
|
||||
: Themes.getAttrColor(launcher, R.attr.allAppsScrimColor);
|
||||
}
|
||||
|
||||
@@ -201,8 +201,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
|
||||
// Only finish if the end target is RECENTS. Otherwise, if the target is
|
||||
// NEW_TASK, startActivityFromRecents will be skipped.
|
||||
if (mLastGestureState.getEndTarget() == RECENTS) {
|
||||
finishRunningRecentsAnimation(false /* toHome */,
|
||||
true /* forceFinish */, null /* forceFinishCb */);
|
||||
finishRunningRecentsAnimation(false /* toHome */);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -342,36 +342,36 @@ public class TouchInteractionService extends Service {
|
||||
|
||||
@BinderThread
|
||||
@Override
|
||||
public void checkNavBarModes() {
|
||||
MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis ->
|
||||
executeForTaskbarManager(TaskbarManager::checkNavBarModes)
|
||||
));
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
@Override
|
||||
public void finishBarAnimations() {
|
||||
MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis ->
|
||||
executeForTaskbarManager(TaskbarManager::finishBarAnimations)
|
||||
));
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
@Override
|
||||
public void touchAutoDim(boolean reset) {
|
||||
MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis ->
|
||||
executeForTaskbarManager(taskbarManager -> taskbarManager.touchAutoDim(reset))
|
||||
));
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
@Override
|
||||
public void transitionTo(@BarTransitions.TransitionMode int barMode,
|
||||
boolean animate) {
|
||||
public void checkNavBarModes(int displayId) {
|
||||
MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis ->
|
||||
executeForTaskbarManager(
|
||||
taskbarManager -> taskbarManager.transitionTo(barMode, animate))
|
||||
));
|
||||
taskbarManager -> taskbarManager.checkNavBarModes(displayId))));
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
@Override
|
||||
public void finishBarAnimations(int displayId) {
|
||||
MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(
|
||||
tis -> executeForTaskbarManager(
|
||||
taskbarManager -> taskbarManager.finishBarAnimations(displayId))));
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
@Override
|
||||
public void touchAutoDim(int displayId, boolean reset) {
|
||||
MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(
|
||||
tis -> executeForTaskbarManager(
|
||||
taskbarManager -> taskbarManager.touchAutoDim(displayId, reset))));
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
@Override
|
||||
public void transitionTo(int displayId, @BarTransitions.TransitionMode int barMode,
|
||||
boolean animate) {
|
||||
MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(
|
||||
tis -> executeForTaskbarManager(
|
||||
taskbarManager -> taskbarManager.transitionTo(displayId, barMode,
|
||||
animate))));
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
|
||||
+9
-10
@@ -16,29 +16,28 @@
|
||||
|
||||
package com.android.quickstep.contextualeducation;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
|
||||
import com.android.launcher3.dagger.LauncherAppSingleton;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.systemui.contextualeducation.GestureType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* A class to update contextual education data via {@link SystemUiProxy}
|
||||
*/
|
||||
@LauncherAppSingleton
|
||||
public class SystemContextualEduStatsManager extends ContextualEduStatsManager {
|
||||
private Context mContext;
|
||||
private final SystemUiProxy mSystemUiProxy;
|
||||
|
||||
public SystemContextualEduStatsManager(Context context) {
|
||||
mContext = context;
|
||||
@Inject
|
||||
public SystemContextualEduStatsManager(SystemUiProxy systemUiProxy) {
|
||||
mSystemUiProxy = systemUiProxy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateEduStats(boolean isTrackpadGesture, GestureType gestureType) {
|
||||
SystemUiProxy.INSTANCE.get(mContext).updateContextualEduStats(isTrackpadGesture,
|
||||
mSystemUiProxy.updateContextualEduStats(isTrackpadGesture,
|
||||
gestureType.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
*/
|
||||
package com.android.quickstep.dagger;
|
||||
|
||||
import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
|
||||
import com.android.launcher3.uioverrides.SystemApiWrapper;
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapperImpl;
|
||||
import com.android.launcher3.util.ApiWrapper;
|
||||
import com.android.launcher3.util.PluginManagerWrapper;
|
||||
import com.android.quickstep.contextualeducation.SystemContextualEduStatsManager;
|
||||
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
@@ -28,4 +30,6 @@ public abstract class QuickStepModule {
|
||||
|
||||
@Binds abstract PluginManagerWrapper bindPluginManagerWrapper(PluginManagerWrapperImpl impl);
|
||||
@Binds abstract ApiWrapper bindApiWrapper(SystemApiWrapper systemApiWrapper);
|
||||
@Binds abstract ContextualEduStatsManager bindContextualEduStatsManager(
|
||||
SystemContextualEduStatsManager manager);
|
||||
}
|
||||
|
||||
@@ -218,6 +218,11 @@ class RecentsWindowManager(context: Context) :
|
||||
)
|
||||
}
|
||||
|
||||
private val onBackInvokedCallback: () -> Unit = {
|
||||
// If we are in live tile mode, launch the live task, otherwise return home
|
||||
recentsView?.runningTaskView?.launchWithAnimation() ?: startHome()
|
||||
}
|
||||
|
||||
private fun cleanupRecentsWindow() {
|
||||
RecentsWindowProtoLogProxy.logCleanup(isShowing())
|
||||
if (isShowing()) {
|
||||
@@ -241,6 +246,10 @@ class RecentsWindowManager(context: Context) :
|
||||
}
|
||||
windowManager.addView(windowView, windowLayoutParams)
|
||||
|
||||
windowView
|
||||
?.findOnBackInvokedDispatcher()
|
||||
?.registerSystemOnBackInvokedCallback(onBackInvokedCallback)
|
||||
|
||||
windowView?.systemUiVisibility =
|
||||
(View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
|
||||
|
||||
+2
-1
@@ -23,6 +23,7 @@ import com.android.launcher3.R
|
||||
import com.android.launcher3.dagger.LauncherAppComponent
|
||||
import com.android.launcher3.dagger.LauncherAppSingleton
|
||||
import com.android.launcher3.util.LauncherModelHelper
|
||||
import com.android.quickstep.dagger.QuickStepModule
|
||||
import com.android.systemui.contextualeducation.GestureType
|
||||
import com.android.systemui.shared.system.InputConsumerController
|
||||
import dagger.BindsInstance
|
||||
@@ -105,7 +106,7 @@ class LauncherSwipeHandlerV2Test {
|
||||
}
|
||||
|
||||
@LauncherAppSingleton
|
||||
@Component
|
||||
@Component(modules = [QuickStepModule::class])
|
||||
interface TestComponent : LauncherAppComponent {
|
||||
@Component.Builder
|
||||
interface Builder : LauncherAppComponent.Builder {
|
||||
|
||||
@@ -104,28 +104,36 @@ class TaplTestsOverviewDesktop : AbstractLauncherUiTest<QuickstepLauncher?>() {
|
||||
|
||||
@Test
|
||||
@PortraitLandscape
|
||||
fun dismissFocusedTask_thenDesktopTask_thenFocusedTaskIsCentered() {
|
||||
fun dismissTasks_whenDesktopTask_IsInTheCenter() {
|
||||
// Create extra activity to be DesktopTaskView
|
||||
startTestActivity(TEST_ACTIVITY_EXTRA)
|
||||
mLauncher.goHome().switchToOverview()
|
||||
|
||||
val desktop = moveTaskToDesktop(TEST_ACTIVITY_EXTRA)
|
||||
var overview = desktop.switchToOverview()
|
||||
|
||||
val overview = desktop.switchToOverview()
|
||||
// Open focused task and go back to Overview to validate whether it has adjacent tasks in
|
||||
// its both sides (grid task on left and desktop tasks at its right side)
|
||||
val focusedTaskOpened = overview.getTestActivityTask(TEST_ACTIVITY_2).open()
|
||||
|
||||
// Dismiss focused task
|
||||
val focusedTask1 = overview.getTestActivityTask(TEST_ACTIVITY_2)
|
||||
assertTaskContentDescription(focusedTask1, TEST_ACTIVITY_2)
|
||||
focusedTask1.dismiss()
|
||||
|
||||
// Dismiss DesktopTaskView
|
||||
// Fling to desktop task and dismiss the focused task to check repositioning of
|
||||
// grid tasks.
|
||||
overview = focusedTaskOpened.switchToOverview().apply { flingBackward() }
|
||||
val desktopTask = overview.currentTask
|
||||
assertWithMessage("The current task is not a Desktop.").that(desktopTask.isDesktop).isTrue()
|
||||
|
||||
// Get focused task (previously opened task) then dismiss this task
|
||||
val focusedTaskInOverview = overview.getTestActivityTask(TEST_ACTIVITY_2)
|
||||
assertTaskContentDescription(focusedTaskInOverview, TEST_ACTIVITY_2)
|
||||
focusedTaskInOverview.dismiss()
|
||||
|
||||
// Dismiss DesktopTask to validate whether the new focused task will take its position
|
||||
desktopTask.dismiss()
|
||||
|
||||
// Dismiss focused task
|
||||
val focusedTask2 = overview.currentTask
|
||||
assertTaskContentDescription(focusedTask2, TEST_ACTIVITY_1)
|
||||
focusedTask2.dismiss()
|
||||
// Dismiss last focused task
|
||||
val lastFocusedTask = overview.currentTask
|
||||
assertTaskContentDescription(lastFocusedTask, TEST_ACTIVITY_1)
|
||||
lastFocusedTask.dismiss()
|
||||
|
||||
assertWithMessage("Still have tasks after dismissing all the tasks")
|
||||
.that(mLauncher.workspace.switchToOverview().hasTasks())
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?android:attr/textColorHint">
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v1.17L10.83,8L20,8v9.17l1.98,1.98c0,-0.05 0.02,-0.1 0.02,-0.16L22,8c0,-1.11 -0.89,-2 -2,-2zM14,6h-4L10,4h4v2zM19,19L8,8 6,6 2.81,2.81 1.39,4.22 3.3,6.13C2.54,6.41 2.01,7.14 2.01,8L2,19c0,1.11 0.89,2 2,2h14.17l1.61,1.61 1.41,-1.41 -0.37,-0.37L19,19zM4,19L4,8h1.17l11,11L4,19z" />
|
||||
</vector>
|
||||
android:pathData="M16,6H20C21.11,6 22,6.89 22,8V18.99C22,19.021 21.994,19.05 21.989,19.077C21.984,19.102 21.98,19.126 21.98,19.15L20,17.17V8H10.83L8,5.17V4C8,2.89 8.89,2 10,2H14C15.11,2 16,2.89 16,4V6ZM10,6H14V4H10V6ZM19,19L8,8L6,6L2.81,2.81L1.39,4.22L3.3,6.13C2.54,6.41 2.01,7.14 2.01,8L2,19C2,20.11 2.89,21 4,21H18.17L19.78,22.61L21.19,21.2L20.82,20.83L19,19ZM4,8V19H16.17L5.17,8H4Z"
|
||||
android:fillColor="?attr/materialColorOnPrimary"
|
||||
android:fillType="evenOdd"/>
|
||||
</vector>
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (C) 2024 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.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="?attr/materialColorOnPrimary"
|
||||
android:pathData="M612,668L668,612L520,464L520,280L440,280L440,496L612,668ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880Z"/>
|
||||
</vector>
|
||||
@@ -18,7 +18,7 @@
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="@dimen/work_fab_radius" />
|
||||
<solid android:color="@color/work_fab_bg_color" />
|
||||
<solid android:color="?attr/materialColorPrimary" />
|
||||
<padding
|
||||
android:left="@dimen/work_mode_fab_background_horizontal_padding"
|
||||
android:right="@dimen/work_mode_fab_background_horizontal_padding"/>
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ Copyright (C) 2024 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.
|
||||
-->
|
||||
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:color="@color/accent_ripple_color">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="@dimen/work_fab_radius" />
|
||||
<solid android:color="?attr/materialColorPrimary" />
|
||||
<padding
|
||||
android:padding="@dimen/work_scheduler_background_padding" />
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
||||
@@ -12,11 +12,9 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.launcher3.allapps.WorkModeSwitch
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/work_mode_toggle"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_height="@dimen/work_fab_height"
|
||||
android:layout_width="wrap_content"
|
||||
android:minHeight="@dimen/work_fab_height"
|
||||
@@ -31,7 +29,6 @@
|
||||
android:layout_marginVertical="@dimen/work_fab_icon_vertical_margin"
|
||||
android:importantForAccessibility="no"
|
||||
android:src="@drawable/ic_corp_off"
|
||||
android:tint="@color/work_fab_icon_color"
|
||||
android:layout_marginStart="@dimen/work_fab_icon_start_margin_expanded"
|
||||
android:scaleType="center"/>
|
||||
<TextView
|
||||
@@ -39,7 +36,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:maxWidth="@dimen/work_fab_width"
|
||||
android:textColor="@color/work_fab_icon_color"
|
||||
android:textColor="?attr/materialColorOnPrimary"
|
||||
android:textSize="14sp"
|
||||
android:includeFontPadding="false"
|
||||
android:textDirection="locale"
|
||||
@@ -48,4 +45,4 @@
|
||||
android:layout_marginEnd="@dimen/work_fab_text_end_margin"
|
||||
android:maxLines="1"
|
||||
style="@style/TextHeadline"/>
|
||||
</com.android.launcher3.allapps.WorkModeSwitch>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<!--
|
||||
~ Copyright (C) 2024 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.
|
||||
-->
|
||||
<com.android.launcher3.allapps.WorkUtilityView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentEnd="true">
|
||||
<ImageButton
|
||||
android:id="@+id/work_scheduler"
|
||||
android:layout_width="@dimen/work_scheduler_size"
|
||||
android:layout_height="@dimen/work_scheduler_size"
|
||||
android:layout_marginBottom="@dimen/work_scheduler_bottom_margin"
|
||||
android:contentDescription="@string/work_scheduler_button_content_description"
|
||||
android:src="@drawable/ic_schedule"
|
||||
android:layout_gravity="end"
|
||||
android:background="@drawable/work_scheduler_background" />
|
||||
<include layout="@layout/work_mode_fab" />
|
||||
</com.android.launcher3.allapps.WorkUtilityView>
|
||||
@@ -53,10 +53,5 @@
|
||||
<color name="widget_picker_add_button_text_color_dark">
|
||||
@android:color/system_accent1_800</color>
|
||||
|
||||
<color name="work_fab_bg_color">
|
||||
@android:color/system_accent1_200</color>
|
||||
<color name="work_fab_icon_color">
|
||||
@android:color/system_accent1_900</color>
|
||||
|
||||
<color name="material_color_on_surface">@android:color/system_neutral1_100</color>
|
||||
</resources>
|
||||
@@ -104,11 +104,6 @@
|
||||
<color name="widget_picker_add_button_text_color_light">
|
||||
@android:color/system_accent1_0</color>
|
||||
|
||||
<color name="work_fab_bg_color">
|
||||
@android:color/system_accent1_200</color>
|
||||
<color name="work_fab_icon_color">
|
||||
@android:color/system_accent1_900</color>
|
||||
|
||||
<color name="overview_foreground_scrim_color">@android:color/system_neutral1_1000</color>
|
||||
|
||||
<color name="material_color_on_surface">@android:color/system_neutral1_900</color>
|
||||
|
||||
@@ -268,6 +268,9 @@
|
||||
defaults to @dimen/taskbar_button_margin_default -->
|
||||
<attr name="inlineNavButtonsEndSpacing" format="reference" />
|
||||
|
||||
<!-- Grid flips row and column count when rotating the device -->
|
||||
<attr name="isDualGrid" format="boolean" />
|
||||
|
||||
<attr name="dbFile" format="string" />
|
||||
<attr name="defaultLayoutId" format="reference" />
|
||||
<attr name="demoModeLayoutId" format="reference" />
|
||||
|
||||
@@ -98,8 +98,6 @@
|
||||
<color name="preload_icon_background_color_dark">#40484D</color>
|
||||
|
||||
<color name="work_turn_on_stroke">?android:attr/colorAccent</color>
|
||||
<color name="work_fab_bg_color">#A8C7FA</color>
|
||||
<color name="work_fab_icon_color">#041E49</color>
|
||||
|
||||
<color name="widget_picker_primary_surface_color_light">#EFEDED</color>
|
||||
<color name="widget_picker_secondary_surface_color_light">#FAF9F8</color>
|
||||
|
||||
@@ -76,7 +76,6 @@
|
||||
<string name="taskbar_view_callbacks_factory_class" translatable="false"></string>
|
||||
<string name="launcher_restore_event_logger_class" translatable="false"></string>
|
||||
<string name="taskbar_edu_tooltip_controller_class" translatable="false"></string>
|
||||
<string name="contextual_edu_manager_class" translatable="false"></string>
|
||||
<!-- Used for determining category of a widget presented in widget recommendations. -->
|
||||
<string name="widget_recommendation_category_provider_class" translatable="false"></string>
|
||||
|
||||
|
||||
@@ -166,6 +166,9 @@
|
||||
<dimen name="work_fab_margin">16dp</dimen>
|
||||
<dimen name="work_fab_margin_bottom">20dp</dimen>
|
||||
<dimen name="work_mode_fab_background_horizontal_padding">16dp</dimen>
|
||||
<dimen name="work_scheduler_background_padding">16dp</dimen>
|
||||
<dimen name="work_scheduler_bottom_margin">8dp</dimen>
|
||||
<dimen name="work_scheduler_size">56dp</dimen>
|
||||
<dimen name="work_profile_footer_padding">20dp</dimen>
|
||||
<dimen name="work_edu_card_margin">16dp</dimen>
|
||||
<dimen name="work_edu_card_radius">16dp</dimen>
|
||||
|
||||
@@ -466,6 +466,8 @@
|
||||
<string name="work_profile_edu_accept">Got it</string>
|
||||
<!-- Info icon unicode for alpha scroller when work edu card is present -->
|
||||
<string name="work_profile_edu_section" translatable="false">\u24D8</string>
|
||||
<!-- Intent for work profiler scheduler -->
|
||||
<string name="work_profile_scheduler_intent" translatable="false"/>
|
||||
|
||||
<!--- heading shown when user opens work apps tab while work apps are paused -->
|
||||
<string name="work_apps_paused_title">Work apps are paused</string>
|
||||
@@ -484,6 +486,8 @@
|
||||
<string name="work_apps_pause_btn_text">Pause work apps</string>
|
||||
<!-- button string shown enable work profile -->
|
||||
<string name="work_apps_enable_btn_text">Unpause</string>
|
||||
<!-- Label for the work profile scheduler button in the work profile screen. [CHAR_LIMIT=40] -->
|
||||
<string name="work_scheduler_button_content_description">Work apps schedule</string>
|
||||
|
||||
<!-- A hint shown in launcher settings develop options filter box -->
|
||||
<string name="developer_options_filter_hint">Filter</string>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<full-backup-content xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<include domain="database" path="launcher.db" />
|
||||
<include domain="database" path="launcher_5_by_8.db" />
|
||||
<include domain="database" path="launcher_6_by_5.db" />
|
||||
<include domain="database" path="launcher_5_by_6.db" />
|
||||
<include domain="database" path="launcher_4_by_6.db" />
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 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.
|
||||
-->
|
||||
|
||||
<favorites xmlns:launcher="http://schemas.android.com/apk/res-auto/com.android.launcher3">
|
||||
|
||||
<!-- Hotseat (We use the screen as the position of the item in the hotseat) -->
|
||||
<!-- Mail Calendar Gallery Store Internet Camera -->
|
||||
<resolve
|
||||
launcher:container="-101"
|
||||
launcher:screen="0"
|
||||
launcher:x="0"
|
||||
launcher:y="0" >
|
||||
<favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_EMAIL;end" />
|
||||
<favorite launcher:uri="mailto:" />
|
||||
</resolve>
|
||||
|
||||
<resolve
|
||||
launcher:container="-101"
|
||||
launcher:screen="1"
|
||||
launcher:x="1"
|
||||
launcher:y="0" >
|
||||
<favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_CALENDAR;end" />
|
||||
</resolve>
|
||||
|
||||
<resolve
|
||||
launcher:container="-101"
|
||||
launcher:screen="2"
|
||||
launcher:x="2"
|
||||
launcher:y="0" >
|
||||
<favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_GALLERY;end" />
|
||||
<favorite launcher:uri="#Intent;type=images/*;end" />
|
||||
</resolve>
|
||||
|
||||
<resolve
|
||||
launcher:container="-101"
|
||||
launcher:screen="3"
|
||||
launcher:x="3"
|
||||
launcher:y="0" >
|
||||
<favorite launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_MARKET;end" />
|
||||
<favorite launcher:uri="market://details?id=com.android.launcher" />
|
||||
</resolve>
|
||||
|
||||
<resolve
|
||||
launcher:container="-101"
|
||||
launcher:screen="4"
|
||||
launcher:x="4"
|
||||
launcher:y="0" >
|
||||
<favorite
|
||||
launcher:uri="#Intent;action=android.intent.action.MAIN;category=android.intent.category.APP_BROWSER;end" />
|
||||
<favorite launcher:uri="http://www.example.com/" />
|
||||
</resolve>
|
||||
|
||||
<!-- Resolve camera intent if GoogleCamera is not available e.g. on emulator -->
|
||||
<resolve
|
||||
launcher:container="-101"
|
||||
launcher:screen="5"
|
||||
launcher:x="5"
|
||||
launcher:y="0" >
|
||||
<favorite launcher:uri="#Intent;action=android.media.action.STILL_IMAGE_CAMERA;end" />
|
||||
<favorite launcher:uri="#Intent;action=android.intent.action.CAMERA_BUTTON;end" />
|
||||
</resolve>
|
||||
|
||||
</favorites>
|
||||
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2024 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.
|
||||
-->
|
||||
|
||||
<device-paddings xmlns:launcher="http://schemas.android.com/apk/res-auto" >
|
||||
|
||||
<device-padding
|
||||
launcher:maxEmptySpace="100dp">
|
||||
<workspaceTopPadding
|
||||
launcher:a="0.31"
|
||||
launcher:b="0"/>
|
||||
<workspaceBottomPadding
|
||||
launcher:a="0.69"
|
||||
launcher:b="0"/>
|
||||
<hotseatBottomPadding
|
||||
launcher:a="0"
|
||||
launcher:b="0"/>
|
||||
</device-padding>
|
||||
|
||||
<device-padding
|
||||
launcher:maxEmptySpace="9999dp">
|
||||
<workspaceTopPadding
|
||||
launcher:a="0.48"
|
||||
launcher:b="0"/>
|
||||
<workspaceBottomPadding
|
||||
launcher:a="0.52"
|
||||
launcher:b="0"/>
|
||||
<hotseatBottomPadding
|
||||
launcher:a="0"
|
||||
launcher:b="0"/>
|
||||
</device-padding>
|
||||
</device-paddings>
|
||||
@@ -827,7 +827,7 @@ public class DeviceProfile {
|
||||
hotseatBorderSpace = cellLayoutBorderSpacePx.y;
|
||||
}
|
||||
|
||||
if (isTablet) {
|
||||
if (shouldShowAllAppsOnSheet()) {
|
||||
allAppsPadding.top = mInsets.top;
|
||||
allAppsShiftRange = heightPx;
|
||||
} else {
|
||||
@@ -1516,6 +1516,11 @@ public class DeviceProfile {
|
||||
}
|
||||
}
|
||||
|
||||
/** Whether All Apps should be presented on a bottom sheet. */
|
||||
public boolean shouldShowAllAppsOnSheet() {
|
||||
return isTablet || Flags.allAppsSheetForHandheld();
|
||||
}
|
||||
|
||||
private void setupAllAppsStyle(Context context) {
|
||||
TypedArray allAppsStyle = context.obtainStyledAttributes(
|
||||
inv.allAppsStyle != INVALID_RESOURCE_HANDLE ? inv.allAppsStyle
|
||||
|
||||
@@ -52,7 +52,6 @@ import androidx.core.content.res.ResourcesCompat;
|
||||
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.icons.DotRenderer;
|
||||
import com.android.launcher3.logging.FileLog;
|
||||
import com.android.launcher3.model.DeviceGridState;
|
||||
import com.android.launcher3.provider.RestoreDbTask;
|
||||
import com.android.launcher3.testing.shared.ResourceUtils;
|
||||
@@ -303,35 +302,6 @@ public class InvariantDeviceProfile implements SafeCloseable {
|
||||
DisplayController.INSTANCE.executeIfCreated(dc -> dc.setPriorityListener(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reinitialize the current grid after a restore, where some grids might now be disabled.
|
||||
*/
|
||||
public void reinitializeAfterRestore(Context context) {
|
||||
String currentGridName = getCurrentGridName(context);
|
||||
String currentDbFile = dbFile;
|
||||
String newGridName = initGrid(context, currentGridName);
|
||||
String newDbFile = dbFile;
|
||||
FileLog.d(TAG, "Reinitializing grid after restore."
|
||||
+ " currentGridName=" + currentGridName
|
||||
+ ", currentDbFile=" + currentDbFile
|
||||
+ ", newGridName=" + newGridName
|
||||
+ ", newDbFile=" + newDbFile);
|
||||
if (!newDbFile.equals(currentDbFile)) {
|
||||
FileLog.d(TAG, "Restored grid is disabled : " + currentGridName
|
||||
+ ", migrating to: " + newGridName
|
||||
+ ", removing all other grid db files");
|
||||
for (String gridDbFile : LauncherFiles.GRID_DB_FILES) {
|
||||
if (gridDbFile.equals(currentDbFile)) {
|
||||
continue;
|
||||
}
|
||||
if (context.getDatabasePath(gridDbFile).delete()) {
|
||||
FileLog.d(TAG, "Removed old grid db file: " + gridDbFile);
|
||||
}
|
||||
}
|
||||
setCurrentGrid(context, newGridName);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getCurrentGridName(Context context) {
|
||||
return LauncherPrefs.get(context).get(GRID_NAME);
|
||||
}
|
||||
@@ -540,7 +510,7 @@ public class InvariantDeviceProfile implements SafeCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
private List<DisplayOption> getPredefinedDeviceProfiles(Context context,
|
||||
private static List<DisplayOption> getPredefinedDeviceProfiles(Context context,
|
||||
String gridName, @DeviceType int deviceType, boolean allowDisabledGrid) {
|
||||
ArrayList<DisplayOption> profiles = new ArrayList<>();
|
||||
|
||||
@@ -554,7 +524,7 @@ public class InvariantDeviceProfile implements SafeCloseable {
|
||||
|
||||
GridOption gridOption = new GridOption(context, Xml.asAttributeSet(parser));
|
||||
if ((gridOption.isEnabled(deviceType) || allowDisabledGrid)
|
||||
&& (Flags.oneGridSpecs() == gridOption.isNewGridOption())) {
|
||||
&& gridOption.filterByFlag(deviceType)) {
|
||||
final int displayDepth = parser.getDepth();
|
||||
while (((type = parser.next()) != XmlPullParser.END_TAG
|
||||
|| parser.getDepth() > displayDepth)
|
||||
@@ -710,7 +680,7 @@ public class InvariantDeviceProfile implements SafeCloseable {
|
||||
return parseAllDefinedGridOptions(context)
|
||||
.stream()
|
||||
.filter(go -> go.isEnabled(deviceType))
|
||||
.filter(go -> (Flags.oneGridSpecs() == go.isNewGridOption()))
|
||||
.filter(go -> go.filterByFlag(deviceType))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@@ -967,6 +937,7 @@ public class InvariantDeviceProfile implements SafeCloseable {
|
||||
private final int demoModeLayoutId;
|
||||
|
||||
private final boolean isScalable;
|
||||
private final boolean mIsDualGrid;
|
||||
private final int devicePaddingId;
|
||||
private final int mWorkspaceSpecsId;
|
||||
private final int mWorkspaceSpecsTwoPanelId;
|
||||
@@ -991,6 +962,7 @@ public class InvariantDeviceProfile implements SafeCloseable {
|
||||
DEVICE_CATEGORY_ALL);
|
||||
mRowCountSpecsId = a.getResourceId(
|
||||
R.styleable.GridDisplayOption_rowCountSpecsId, INVALID_RESOURCE_HANDLE);
|
||||
mIsDualGrid = a.getBoolean(R.styleable.GridDisplayOption_isDualGrid, false);
|
||||
if (mRowCountSpecsId != INVALID_RESOURCE_HANDLE) {
|
||||
ResourceHelper resourceHelper = new ResourceHelper(context, mRowCountSpecsId);
|
||||
NumRows numR = getRowCount(resourceHelper, context, deviceCategory);
|
||||
@@ -1154,6 +1126,13 @@ public class InvariantDeviceProfile implements SafeCloseable {
|
||||
public boolean isNewGridOption() {
|
||||
return mRowCountSpecsId != INVALID_RESOURCE_HANDLE;
|
||||
}
|
||||
|
||||
public boolean filterByFlag(int deviceType) {
|
||||
if (deviceType == TYPE_TABLET) {
|
||||
return Flags.oneGridRotationHandling() == mIsDualGrid;
|
||||
}
|
||||
return Flags.oneGridSpecs() == isNewGridOption();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class NumRows {
|
||||
|
||||
@@ -16,6 +16,7 @@ public class LauncherFiles {
|
||||
private static final String XML = ".xml";
|
||||
|
||||
public static final String LAUNCHER_DB = "launcher.db";
|
||||
public static final String LAUNCHER_5_BY_8_DB = "launcher_5_by_8.db";
|
||||
public static final String LAUNCHER_6_BY_5_DB = "launcher_6_by_5.db";
|
||||
public static final String LAUNCHER_4_BY_5_DB = "launcher_4_by_5.db";
|
||||
public static final String LAUNCHER_4_BY_6_DB = "launcher_4_by_6.db";
|
||||
@@ -35,6 +36,7 @@ public class LauncherFiles {
|
||||
|
||||
public static final List<String> GRID_DB_FILES = Collections.unmodifiableList(Arrays.asList(
|
||||
LAUNCHER_DB,
|
||||
LAUNCHER_5_BY_8_DB,
|
||||
LAUNCHER_6_BY_5_DB,
|
||||
LAUNCHER_4_BY_5_DB,
|
||||
LAUNCHER_4_BY_6_DB,
|
||||
|
||||
@@ -375,8 +375,14 @@ public abstract class LauncherState implements BaseState<LauncherState> {
|
||||
}
|
||||
|
||||
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
|
||||
if ((this != NORMAL && this != HINT_STATE)
|
||||
|| !launcher.getDeviceProfile().shouldFadeAdjacentWorkspaceScreens()) {
|
||||
DeviceProfile dp = launcher.getDeviceProfile();
|
||||
boolean shouldFadeAdjacentScreens = (this == NORMAL || this == HINT_STATE)
|
||||
&& dp.shouldFadeAdjacentWorkspaceScreens();
|
||||
// Avoid showing adjacent screens behind handheld All Apps sheet.
|
||||
if (Flags.allAppsSheetForHandheld() && dp.isPhone && this == ALL_APPS) {
|
||||
shouldFadeAdjacentScreens = true;
|
||||
}
|
||||
if (!shouldFadeAdjacentScreens) {
|
||||
return DEFAULT_ALPHA_PROVIDER;
|
||||
}
|
||||
final int centerPage = launcher.getWorkspace().getNextPage();
|
||||
|
||||
@@ -47,7 +47,6 @@ import android.os.Parcelable;
|
||||
import android.os.Process;
|
||||
import android.os.UserManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.KeyEvent;
|
||||
@@ -115,19 +114,6 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
ScrimView.ScrimDrawingController {
|
||||
|
||||
|
||||
public static final FloatProperty<ActivityAllAppsContainerView<?>> BOTTOM_SHEET_ALPHA =
|
||||
new FloatProperty<>("bottomSheetAlpha") {
|
||||
@Override
|
||||
public Float get(ActivityAllAppsContainerView<?> containerView) {
|
||||
return containerView.mBottomSheetAlpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(ActivityAllAppsContainerView<?> containerView, float v) {
|
||||
containerView.setBottomSheetAlpha(v);
|
||||
}
|
||||
};
|
||||
|
||||
public static final float PULL_MULTIPLIER = .02f;
|
||||
public static final float FLING_VELOCITY_MULTIPLIER = 1200f;
|
||||
protected static final String BUNDLE_KEY_CURRENT_PAGE = "launcher.allapps.current_page";
|
||||
@@ -191,8 +177,6 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
private ScrimView mScrimView;
|
||||
private int mHeaderColor;
|
||||
private int mBottomSheetBackgroundColor;
|
||||
private float mBottomSheetAlpha = 1f;
|
||||
private boolean mForceBottomSheetVisible;
|
||||
private int mTabsProtectionAlpha;
|
||||
@Nullable private AllAppsTransitionController mAllAppsTransitionController;
|
||||
|
||||
@@ -351,20 +335,6 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
return mSearchUiManager;
|
||||
}
|
||||
|
||||
public View getBottomSheetBackground() {
|
||||
return mBottomSheetBackground;
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporarily force the bottom sheet to be visible on non-tablets.
|
||||
*
|
||||
* @param force {@code true} means bottom sheet will be visible on phones until {@code reset()}.
|
||||
*/
|
||||
public void forceBottomSheetVisible(boolean force) {
|
||||
mForceBottomSheetVisible = force;
|
||||
updateBackgroundVisibility(mActivityContext.getDeviceProfile());
|
||||
}
|
||||
|
||||
public View getSearchView() {
|
||||
return mSearchContainer;
|
||||
}
|
||||
@@ -496,7 +466,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
if (mHeader != null && mHeader.getVisibility() == VISIBLE) {
|
||||
mHeader.reset(animate);
|
||||
}
|
||||
forceBottomSheetVisible(false);
|
||||
updateBackgroundVisibility(mActivityContext.getDeviceProfile());
|
||||
// Reset the base recycler view after transitioning home.
|
||||
updateHeaderScroll(0);
|
||||
if (exitSearch) {
|
||||
@@ -726,7 +696,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
post(() -> mAH.get(AdapterHolder.WORK).applyPadding());
|
||||
|
||||
} else {
|
||||
mWorkManager.detachWorkModeSwitch();
|
||||
mWorkManager.detachWorkUtilityViews();
|
||||
mViewPager = null;
|
||||
}
|
||||
|
||||
@@ -1002,18 +972,13 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
}
|
||||
|
||||
protected void updateBackgroundVisibility(DeviceProfile deviceProfile) {
|
||||
boolean visible = deviceProfile.isTablet || mForceBottomSheetVisible;
|
||||
mBottomSheetBackground.setVisibility(visible ? View.VISIBLE : View.GONE);
|
||||
// Note: For tablets, the opaque background and header protection are added in drawOnScrim.
|
||||
mBottomSheetBackground.setVisibility(
|
||||
deviceProfile.shouldShowAllAppsOnSheet() ? View.VISIBLE : View.GONE);
|
||||
// Note: The opaque sheet background and header protection are added in drawOnScrim.
|
||||
// For the taskbar entrypoint, the scrim is drawn by its abstract slide in view container,
|
||||
// so its header protection is derived from this scrim instead.
|
||||
}
|
||||
|
||||
private void setBottomSheetAlpha(float alpha) {
|
||||
// Bottom sheet alpha is always 1 for tablets.
|
||||
mBottomSheetAlpha = mActivityContext.getDeviceProfile().isTablet ? 1f : alpha;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void onAppsUpdated() {
|
||||
mHasWorkApps = Stream.of(mAllAppsStore.getApps())
|
||||
@@ -1151,8 +1116,8 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
applyAdapterSideAndBottomPaddings(grid);
|
||||
|
||||
MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
|
||||
// Ignore left/right insets on tablet because we are already centered in-screen.
|
||||
if (grid.isTablet) {
|
||||
// Ignore left/right insets on bottom sheet because we are already centered in-screen.
|
||||
if (grid.shouldShowAllAppsOnSheet()) {
|
||||
mlp.leftMargin = mlp.rightMargin = 0;
|
||||
} else {
|
||||
mlp.leftMargin = insets.left;
|
||||
@@ -1257,8 +1222,8 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
/** Called in Launcher#bindStringCache() to update the UI when cache is updated. */
|
||||
public void updateWorkUI() {
|
||||
setDeviceManagementResources();
|
||||
if (mWorkManager.getWorkModeSwitch() != null) {
|
||||
mWorkManager.getWorkModeSwitch().updateStringFromCache();
|
||||
if (mWorkManager.getWorkUtilityView() != null) {
|
||||
mWorkManager.getWorkUtilityView().updateStringFromCache();
|
||||
}
|
||||
inflateWorkCardsIfNeeded();
|
||||
}
|
||||
@@ -1398,7 +1363,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
// Draw full background panel for tablets.
|
||||
if (hasBottomSheet) {
|
||||
mHeaderPaint.setColor(mBottomSheetBackgroundColor);
|
||||
mHeaderPaint.setAlpha((int) (255 * mBottomSheetAlpha));
|
||||
mHeaderPaint.setAlpha(255);
|
||||
|
||||
mTmpRectF.set(
|
||||
leftWithScale,
|
||||
@@ -1581,8 +1546,8 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
void applyPadding() {
|
||||
if (mRecyclerView != null) {
|
||||
int bottomOffset = 0;
|
||||
if (isWork() && mWorkManager.getWorkModeSwitch() != null) {
|
||||
bottomOffset = mInsets.bottom + mWorkManager.getWorkModeSwitch().getHeight();
|
||||
if (isWork() && mWorkManager.getWorkUtilityView() != null) {
|
||||
bottomOffset = mInsets.bottom + mWorkManager.getWorkUtilityView().getHeight();
|
||||
} else if (isMain() && mPrivateProfileManager != null) {
|
||||
Optional<AdapterItem> privateSpaceHeaderItem = mAppsList.getAdapterItems()
|
||||
.stream()
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package com.android.launcher3.allapps;
|
||||
|
||||
import static com.android.app.animation.Interpolators.DECELERATE_1_7;
|
||||
import static com.android.app.animation.Interpolators.INSTANT;
|
||||
import static com.android.app.animation.Interpolators.LINEAR;
|
||||
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
|
||||
@@ -28,7 +27,6 @@ import static com.android.launcher3.UtilitiesKt.CLIP_CHILDREN_FALSE_MODIFIER;
|
||||
import static com.android.launcher3.UtilitiesKt.modifyAttributesOnViewTree;
|
||||
import static com.android.launcher3.UtilitiesKt.restoreAttributesOnViewTree;
|
||||
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_BOTTOM_SHEET_FADE;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
|
||||
import static com.android.launcher3.util.SystemUiController.FLAG_DARK_NAV;
|
||||
@@ -106,7 +104,7 @@ public class AllAppsTransitionController
|
||||
|
||||
@Override
|
||||
public Float get(AllAppsTransitionController controller) {
|
||||
if (controller.mIsTablet) {
|
||||
if (controller.mShouldShowAllAppsOnSheet) {
|
||||
return controller.mAppsView.getActiveRecyclerView().getTranslationY();
|
||||
} else {
|
||||
return controller.getAppsViewPullbackTranslationY().getValue();
|
||||
@@ -115,7 +113,7 @@ public class AllAppsTransitionController
|
||||
|
||||
@Override
|
||||
public void setValue(AllAppsTransitionController controller, float translation) {
|
||||
if (controller.mIsTablet) {
|
||||
if (controller.mShouldShowAllAppsOnSheet) {
|
||||
controller.mAppsView.getActiveRecyclerView().setTranslationY(translation);
|
||||
controller.getAppsViewPullbackTranslationY().setValue(
|
||||
ALL_APPS_PULL_BACK_TRANSLATION_DEFAULT);
|
||||
@@ -134,7 +132,7 @@ public class AllAppsTransitionController
|
||||
|
||||
@Override
|
||||
public Float get(AllAppsTransitionController controller) {
|
||||
if (controller.mIsTablet) {
|
||||
if (controller.mShouldShowAllAppsOnSheet) {
|
||||
return controller.mAppsView.getActiveRecyclerView().getAlpha();
|
||||
} else {
|
||||
return controller.getAppsViewPullbackAlpha().getValue();
|
||||
@@ -143,7 +141,7 @@ public class AllAppsTransitionController
|
||||
|
||||
@Override
|
||||
public void setValue(AllAppsTransitionController controller, float alpha) {
|
||||
if (controller.mIsTablet) {
|
||||
if (controller.mShouldShowAllAppsOnSheet) {
|
||||
controller.mAppsView.getActiveRecyclerView().setAlpha(alpha);
|
||||
controller.getAppsViewPullbackAlpha().setValue(
|
||||
ALL_APPS_PULL_BACK_ALPHA_DEFAULT);
|
||||
@@ -168,6 +166,7 @@ public class AllAppsTransitionController
|
||||
@Nullable private Animator.AnimatorListener mAllAppsSearchBackAnimationListener;
|
||||
|
||||
private boolean mIsVerticalLayout;
|
||||
private boolean mShouldShowAllAppsOnSheet;
|
||||
|
||||
// Animation in this class is controlled by a single variable {@link mProgress}.
|
||||
// Visually, it represents top y coordinate of the all apps container if multiplied with
|
||||
@@ -183,8 +182,6 @@ public class AllAppsTransitionController
|
||||
private MultiValueAlpha mAppsViewAlpha;
|
||||
private MultiPropertyFactory<View> mAppsViewTranslationY;
|
||||
|
||||
private boolean mIsTablet;
|
||||
|
||||
private boolean mHasScaleEffect;
|
||||
private final VibratorWrapper mVibratorWrapper;
|
||||
|
||||
@@ -193,7 +190,7 @@ public class AllAppsTransitionController
|
||||
DeviceProfile dp = mLauncher.getDeviceProfile();
|
||||
mProgress = 1f;
|
||||
mIsVerticalLayout = dp.isVerticalBarLayout();
|
||||
mIsTablet = dp.isTablet;
|
||||
mShouldShowAllAppsOnSheet = dp.shouldShowAllAppsOnSheet();
|
||||
mNavScrimFlag = Themes.getAttrBoolean(l, R.attr.isMainColorDark)
|
||||
? FLAG_DARK_NAV : FLAG_LIGHT_NAV;
|
||||
|
||||
@@ -217,7 +214,7 @@ public class AllAppsTransitionController
|
||||
mLauncher.getWorkspace().getPageIndicator().setTranslationY(0);
|
||||
}
|
||||
|
||||
mIsTablet = dp.isTablet;
|
||||
mShouldShowAllAppsOnSheet = dp.shouldShowAllAppsOnSheet();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -395,10 +392,6 @@ public class AllAppsTransitionController
|
||||
setter.setFloat(getAppsViewPullbackAlpha(), MultiPropertyFactory.MULTI_PROPERTY_VALUE,
|
||||
hasAllAppsContent ? 1 : 0, allAppsFade);
|
||||
|
||||
setter.setFloat(mLauncher.getAppsView(),
|
||||
ActivityAllAppsContainerView.BOTTOM_SHEET_ALPHA, hasAllAppsContent ? 1 : 0,
|
||||
config.getInterpolator(ANIM_ALL_APPS_BOTTOM_SHEET_FADE, INSTANT));
|
||||
|
||||
boolean shouldProtectHeader = !config.hasAnimationFlag(StateAnimationConfig.SKIP_SCRIM)
|
||||
&& (ALL_APPS == state || mLauncher.getStateManager().getState() == ALL_APPS);
|
||||
mScrimView.setDrawingController(shouldProtectHeader ? mAppsView : null);
|
||||
|
||||
@@ -58,7 +58,7 @@ public class WorkProfileManager extends UserProfileManager
|
||||
implements PersonalWorkSlidingTabStrip.OnActivePageChangedListener {
|
||||
private static final String TAG = "WorkProfileManager";
|
||||
private final ActivityAllAppsContainerView<?> mAllApps;
|
||||
private WorkModeSwitch mWorkModeSwitch;
|
||||
private WorkUtilityView mWorkUtilityView;
|
||||
private final Predicate<UserHandle> mWorkProfileMatcher;
|
||||
|
||||
public WorkProfileManager(
|
||||
@@ -79,15 +79,15 @@ public class WorkProfileManager extends UserProfileManager
|
||||
|
||||
@Override
|
||||
public void onActivePageChanged(int page) {
|
||||
updateWorkFAB(page);
|
||||
updateWorkUtilityViews(page);
|
||||
}
|
||||
|
||||
private void updateWorkFAB(int page) {
|
||||
if (mWorkModeSwitch != null) {
|
||||
private void updateWorkUtilityViews(int page) {
|
||||
if (mWorkUtilityView != null) {
|
||||
if (page == MAIN || page == SEARCH) {
|
||||
mWorkModeSwitch.animateVisibility(false);
|
||||
mWorkUtilityView.animateVisibility(false);
|
||||
} else if (page == WORK && getCurrentState() == STATE_ENABLED) {
|
||||
mWorkModeSwitch.animateVisibility(true);
|
||||
mWorkUtilityView.animateVisibility(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,10 +104,10 @@ public class WorkProfileManager extends UserProfileManager
|
||||
}
|
||||
boolean isEnabled = !mAllApps.getAppsStore().hasModelFlag(quietModeFlag);
|
||||
updateCurrentState(isEnabled ? STATE_ENABLED : STATE_DISABLED);
|
||||
if (mWorkModeSwitch != null) {
|
||||
if (mWorkUtilityView != null) {
|
||||
// reset the position of the button and clear IME insets.
|
||||
mWorkModeSwitch.getImeInsets().setEmpty();
|
||||
mWorkModeSwitch.updateTranslationY();
|
||||
mWorkUtilityView.getImeInsets().setEmpty();
|
||||
mWorkUtilityView.updateTranslationY();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,54 +116,54 @@ public class WorkProfileManager extends UserProfileManager
|
||||
if (getAH() != null) {
|
||||
getAH().mAppsList.updateAdapterItems();
|
||||
}
|
||||
if (mWorkModeSwitch != null) {
|
||||
updateWorkFAB(mAllApps.getCurrentPage());
|
||||
if (mWorkUtilityView != null) {
|
||||
updateWorkUtilityViews(mAllApps.getCurrentPage());
|
||||
}
|
||||
if (getCurrentState() == STATE_ENABLED) {
|
||||
attachWorkModeSwitch();
|
||||
attachWorkUtilityViews();
|
||||
} else if (getCurrentState() == STATE_DISABLED) {
|
||||
detachWorkModeSwitch();
|
||||
detachWorkUtilityViews();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and attaches for profile toggle button to {@link ActivityAllAppsContainerView}
|
||||
*/
|
||||
public boolean attachWorkModeSwitch() {
|
||||
public boolean attachWorkUtilityViews() {
|
||||
if (!mAllApps.getAppsStore().hasModelFlag(
|
||||
FLAG_HAS_SHORTCUT_PERMISSION | FLAG_QUIET_MODE_CHANGE_PERMISSION)) {
|
||||
Log.e(TAG, "unable to attach work mode switch; Missing required permissions");
|
||||
return false;
|
||||
}
|
||||
if (mWorkModeSwitch == null) {
|
||||
mWorkModeSwitch = (WorkModeSwitch) mAllApps.getLayoutInflater().inflate(
|
||||
R.layout.work_mode_fab, mAllApps, false);
|
||||
if (mWorkUtilityView == null) {
|
||||
mWorkUtilityView = (WorkUtilityView) mAllApps.getLayoutInflater().inflate(
|
||||
R.layout.work_mode_utility_view, mAllApps, false);
|
||||
}
|
||||
if (mWorkModeSwitch.getParent() == null) {
|
||||
mAllApps.addView(mWorkModeSwitch);
|
||||
if (mWorkUtilityView.getParent() == null) {
|
||||
mAllApps.addView(mWorkUtilityView);
|
||||
}
|
||||
if (mAllApps.getCurrentPage() != WORK) {
|
||||
mWorkModeSwitch.animateVisibility(false);
|
||||
mWorkUtilityView.animateVisibility(false);
|
||||
}
|
||||
if (getAH() != null) {
|
||||
getAH().applyPadding();
|
||||
}
|
||||
mWorkModeSwitch.setOnClickListener(this::onWorkFabClicked);
|
||||
mWorkUtilityView.setOnClickListener(this::onWorkFabClicked);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Removes work profile toggle button from {@link ActivityAllAppsContainerView}
|
||||
*/
|
||||
public void detachWorkModeSwitch() {
|
||||
if (mWorkModeSwitch != null && mWorkModeSwitch.getParent() == mAllApps) {
|
||||
mAllApps.removeView(mWorkModeSwitch);
|
||||
public void detachWorkUtilityViews() {
|
||||
if (mWorkUtilityView != null && mWorkUtilityView.getParent() == mAllApps) {
|
||||
mAllApps.removeView(mWorkUtilityView);
|
||||
}
|
||||
mWorkModeSwitch = null;
|
||||
mWorkUtilityView = null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public WorkModeSwitch getWorkModeSwitch() {
|
||||
return mWorkModeSwitch;
|
||||
public WorkUtilityView getWorkUtilityView() {
|
||||
return mWorkUtilityView;
|
||||
}
|
||||
|
||||
private ActivityAllAppsContainerView.AdapterHolder getAH() {
|
||||
@@ -199,7 +199,7 @@ public class WorkProfileManager extends UserProfileManager
|
||||
}
|
||||
|
||||
private void onWorkFabClicked(View view) {
|
||||
if (getCurrentState() == STATE_ENABLED && mWorkModeSwitch.isEnabled()) {
|
||||
if (getCurrentState() == STATE_ENABLED && mWorkUtilityView.isEnabled()) {
|
||||
logEvents(LAUNCHER_TURN_OFF_WORK_APPS_TAP);
|
||||
setWorkProfileEnabled(false);
|
||||
}
|
||||
@@ -216,7 +216,7 @@ public class WorkProfileManager extends UserProfileManager
|
||||
}
|
||||
@Override
|
||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
||||
WorkModeSwitch fab = getWorkModeSwitch();
|
||||
WorkUtilityView fab = getWorkUtilityView();
|
||||
if (fab == null){
|
||||
return;
|
||||
}
|
||||
|
||||
+112
-29
@@ -21,11 +21,13 @@ import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Rect;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
@@ -36,6 +38,7 @@ import androidx.core.view.WindowInsetsCompat;
|
||||
|
||||
import com.android.app.animation.Interpolators;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Flags;
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
@@ -43,10 +46,13 @@ import com.android.launcher3.anim.AnimatedPropertySetter;
|
||||
import com.android.launcher3.anim.KeyboardInsetAnimationCallback;
|
||||
import com.android.launcher3.model.StringCache;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Work profile toggle switch shown at the bottom of AllApps work tab
|
||||
* Work profile utility ViewGroup that is shown at the bottom of AllApps work tab
|
||||
*/
|
||||
public class WorkModeSwitch extends LinearLayout implements Insettable,
|
||||
public class WorkUtilityView extends LinearLayout implements Insettable,
|
||||
KeyboardInsetAnimationCallback.KeyboardInsetListener {
|
||||
|
||||
private static final int TEXT_EXPAND_OPACITY_DURATION = 300;
|
||||
@@ -54,10 +60,14 @@ public class WorkModeSwitch extends LinearLayout implements Insettable,
|
||||
private static final int EXPAND_COLLAPSE_DURATION = 300;
|
||||
private static final int TEXT_ALPHA_EXPAND_DELAY = 80;
|
||||
private static final int TEXT_ALPHA_COLLAPSE_DELAY = 0;
|
||||
private static final int WORK_SCHEDULER_OPACITY_DURATION =
|
||||
(int) (EXPAND_COLLAPSE_DURATION * 0.75f);
|
||||
private static final int FLAG_FADE_ONGOING = 1 << 1;
|
||||
private static final int FLAG_TRANSLATION_ONGOING = 1 << 2;
|
||||
private static final int FLAG_IS_EXPAND = 1 << 3;
|
||||
private static final int SCROLL_THRESHOLD_DP = 10;
|
||||
private static final float WORK_SCHEDULER_SCALE_MIN = 0.25f;
|
||||
private static final float WORK_SCHEDULER_SCALE_MAX = 1f;
|
||||
|
||||
private final Rect mInsets = new Rect();
|
||||
private final Rect mImeInsets = new Rect();
|
||||
@@ -67,22 +77,25 @@ public class WorkModeSwitch extends LinearLayout implements Insettable,
|
||||
private final int mTextMarginStart;
|
||||
private final int mTextMarginEnd;
|
||||
private final int mIconMarginStart;
|
||||
private final String mWorkSchedulerIntentAction;
|
||||
|
||||
// Threshold when user scrolls up/down to determine when should button extend/collapse
|
||||
private final int mScrollThreshold;
|
||||
private TextView mTextView;
|
||||
private ImageView mIcon;
|
||||
private ValueAnimator mPauseFABAnim;
|
||||
private TextView mPauseText;
|
||||
private ImageView mWorkIcon;
|
||||
private ImageButton mSchedulerButton;
|
||||
|
||||
public WorkModeSwitch(@NonNull Context context) {
|
||||
public WorkUtilityView(@NonNull Context context) {
|
||||
this(context, null, 0);
|
||||
}
|
||||
|
||||
public WorkModeSwitch(@NonNull Context context, @NonNull AttributeSet attrs) {
|
||||
public WorkUtilityView(@NonNull Context context, @NonNull AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public WorkModeSwitch(@NonNull Context context, @NonNull AttributeSet attrs, int defStyleAttr) {
|
||||
public WorkUtilityView(@NonNull Context context, @NonNull AttributeSet attrs,
|
||||
int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mContext = context;
|
||||
mScrollThreshold = Utilities.dpToPx(SCROLL_THRESHOLD_DP);
|
||||
@@ -93,14 +106,17 @@ public class WorkModeSwitch extends LinearLayout implements Insettable,
|
||||
R.dimen.work_fab_text_end_margin);
|
||||
mIconMarginStart = mContext.getResources().getDimensionPixelSize(
|
||||
R.dimen.work_fab_icon_start_margin_expanded);
|
||||
mWorkSchedulerIntentAction = mContext.getResources().getString(
|
||||
R.string.work_profile_scheduler_intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
mTextView = findViewById(R.id.pause_text);
|
||||
mIcon = findViewById(R.id.work_icon);
|
||||
mPauseText = findViewById(R.id.pause_text);
|
||||
mWorkIcon = findViewById(R.id.work_icon);
|
||||
mSchedulerButton = findViewById(R.id.work_scheduler);
|
||||
setSelected(true);
|
||||
KeyboardInsetAnimationCallback keyboardInsetAnimationCallback =
|
||||
new KeyboardInsetAnimationCallback(this);
|
||||
@@ -109,6 +125,12 @@ public class WorkModeSwitch extends LinearLayout implements Insettable,
|
||||
addFlag(FLAG_IS_EXPAND);
|
||||
setInsets(mActivityContext.getDeviceProfile().getInsets());
|
||||
updateStringFromCache();
|
||||
mSchedulerButton.setVisibility(GONE);
|
||||
if (shouldUseScheduler()) {
|
||||
mSchedulerButton.setVisibility(VISIBLE);
|
||||
mSchedulerButton.setOnClickListener(view ->
|
||||
mContext.startActivity(new Intent(mWorkSchedulerIntentAction)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -166,8 +188,10 @@ public class WorkModeSwitch extends LinearLayout implements Insettable,
|
||||
WindowInsetsCompat.toWindowInsetsCompat(insets, this);
|
||||
if (windowInsetsCompat.isVisible(WindowInsetsCompat.Type.ime())) {
|
||||
setInsets(mImeInsets, windowInsetsCompat.getInsets(WindowInsetsCompat.Type.ime()));
|
||||
shrink();
|
||||
} else {
|
||||
mImeInsets.setEmpty();
|
||||
extend();
|
||||
}
|
||||
updateTranslationY();
|
||||
return super.onApplyWindowInsets(insets);
|
||||
@@ -183,15 +207,63 @@ public class WorkModeSwitch extends LinearLayout implements Insettable,
|
||||
super.setTranslationY(Math.min(translationY, -mInsets.bottom));
|
||||
}
|
||||
|
||||
private ValueAnimator animateSchedulerScale(boolean isExpanding) {
|
||||
float scaleFrom = isExpanding ? WORK_SCHEDULER_SCALE_MIN : WORK_SCHEDULER_SCALE_MAX;
|
||||
float scaleTo = isExpanding ? WORK_SCHEDULER_SCALE_MAX : WORK_SCHEDULER_SCALE_MIN;
|
||||
ValueAnimator schedulerScaleAnim = ObjectAnimator.ofFloat(scaleFrom, scaleTo);
|
||||
schedulerScaleAnim.setDuration(EXPAND_COLLAPSE_DURATION);
|
||||
schedulerScaleAnim.setInterpolator(Interpolators.STANDARD);
|
||||
schedulerScaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator valueAnimator) {
|
||||
float scale = (float) valueAnimator.getAnimatedValue();
|
||||
mSchedulerButton.setScaleX(scale);
|
||||
mSchedulerButton.setScaleY(scale);
|
||||
}
|
||||
});
|
||||
schedulerScaleAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
if (isExpanding) {
|
||||
mSchedulerButton.setVisibility(VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private void animatePillTransition(boolean isExpanding) {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (!isExpanding) {
|
||||
mSchedulerButton.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
});
|
||||
return schedulerScaleAnim;
|
||||
}
|
||||
|
||||
private ValueAnimator animateSchedulerAlpha(boolean isExpanding) {
|
||||
float alphaFrom = isExpanding ? 0 : 1;
|
||||
float alphaTo = isExpanding ? 1 : 0;
|
||||
ValueAnimator schedulerAlphaAnim = ObjectAnimator.ofFloat(alphaFrom, alphaTo);
|
||||
schedulerAlphaAnim.setDuration(WORK_SCHEDULER_OPACITY_DURATION);
|
||||
schedulerAlphaAnim.setStartDelay(isExpanding ? 0 :
|
||||
EXPAND_COLLAPSE_DURATION - WORK_SCHEDULER_OPACITY_DURATION);
|
||||
schedulerAlphaAnim.setInterpolator(Interpolators.STANDARD);
|
||||
schedulerAlphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator valueAnimator) {
|
||||
mSchedulerButton.setAlpha((float) valueAnimator.getAnimatedValue());
|
||||
}
|
||||
});
|
||||
return schedulerAlphaAnim;
|
||||
}
|
||||
|
||||
private void animateWorkUtilityViews(boolean isExpanding) {
|
||||
if (!shouldAnimate(isExpanding)) {
|
||||
return;
|
||||
}
|
||||
AnimatorSet animatorSet = new AnimatedPropertySetter().buildAnim();
|
||||
mTextView.measure(0,0);
|
||||
int currentWidth = mTextView.getWidth();
|
||||
int fullWidth = mTextView.getMeasuredWidth();
|
||||
mPauseText.measure(0,0);
|
||||
int currentWidth = mPauseText.getWidth();
|
||||
int fullWidth = mPauseText.getMeasuredWidth();
|
||||
float from = isExpanding ? 0 : currentWidth;
|
||||
float to = isExpanding ? fullWidth : 0;
|
||||
mPauseFABAnim = ObjectAnimator.ofFloat(from, to);
|
||||
@@ -203,15 +275,15 @@ public class WorkModeSwitch extends LinearLayout implements Insettable,
|
||||
float translation = (float) valueAnimator.getAnimatedValue();
|
||||
float translationFraction = translation / fullWidth;
|
||||
ViewGroup.MarginLayoutParams textViewLayoutParams =
|
||||
(ViewGroup.MarginLayoutParams) mTextView.getLayoutParams();
|
||||
(ViewGroup.MarginLayoutParams) mPauseText.getLayoutParams();
|
||||
textViewLayoutParams.width = (int) translation;
|
||||
textViewLayoutParams.setMarginStart((int) (mTextMarginStart * translationFraction));
|
||||
textViewLayoutParams.setMarginEnd((int) (mTextMarginEnd * translationFraction));
|
||||
mTextView.setLayoutParams(textViewLayoutParams);
|
||||
mPauseText.setLayoutParams(textViewLayoutParams);
|
||||
ViewGroup.MarginLayoutParams iconLayoutParams =
|
||||
(ViewGroup.MarginLayoutParams) mIcon.getLayoutParams();
|
||||
(ViewGroup.MarginLayoutParams) mWorkIcon.getLayoutParams();
|
||||
iconLayoutParams.setMarginStart((int) (mIconMarginStart * translationFraction));
|
||||
mIcon.setLayoutParams(iconLayoutParams);
|
||||
mWorkIcon.setLayoutParams(iconLayoutParams);
|
||||
}
|
||||
});
|
||||
mPauseFABAnim.addListener(new AnimatorListenerAdapter() {
|
||||
@@ -220,21 +292,28 @@ public class WorkModeSwitch extends LinearLayout implements Insettable,
|
||||
if (isExpanding) {
|
||||
addFlag(FLAG_IS_EXPAND);
|
||||
} else {
|
||||
mTextView.setVisibility(GONE);
|
||||
mPauseText.setVisibility(GONE);
|
||||
removeFlag(FLAG_IS_EXPAND);
|
||||
}
|
||||
mTextView.setHorizontallyScrolling(false);
|
||||
mTextView.setEllipsize(TextUtils.TruncateAt.END);
|
||||
mPauseText.setHorizontallyScrolling(false);
|
||||
mPauseText.setEllipsize(TextUtils.TruncateAt.END);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animator) {
|
||||
mTextView.setHorizontallyScrolling(true);
|
||||
mTextView.setVisibility(VISIBLE);
|
||||
mTextView.setEllipsize(null);
|
||||
mPauseText.setHorizontallyScrolling(true);
|
||||
mPauseText.setVisibility(VISIBLE);
|
||||
mPauseText.setEllipsize(null);
|
||||
}
|
||||
});
|
||||
animatorSet.playTogether(mPauseFABAnim, updatePauseTextAlpha(isExpanding));
|
||||
ArrayList<Animator> animatorList = new ArrayList<>();
|
||||
animatorList.add(mPauseFABAnim);
|
||||
animatorList.add(updatePauseTextAlpha(isExpanding));
|
||||
if (shouldUseScheduler()) {
|
||||
animatorList.add(animateSchedulerScale(isExpanding));
|
||||
animatorList.add(animateSchedulerAlpha(isExpanding));
|
||||
}
|
||||
animatorSet.playTogether(animatorList);
|
||||
animatorSet.start();
|
||||
}
|
||||
|
||||
@@ -250,7 +329,7 @@ public class WorkModeSwitch extends LinearLayout implements Insettable,
|
||||
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator valueAnimator) {
|
||||
mTextView.setAlpha((float) valueAnimator.getAnimatedValue());
|
||||
mPauseText.setAlpha((float) valueAnimator.getAnimatedValue());
|
||||
}
|
||||
});
|
||||
return alphaAnim;
|
||||
@@ -287,11 +366,11 @@ public class WorkModeSwitch extends LinearLayout implements Insettable,
|
||||
}
|
||||
|
||||
public void extend() {
|
||||
animatePillTransition(true);
|
||||
animateWorkUtilityViews(true);
|
||||
}
|
||||
|
||||
public void shrink(){
|
||||
animatePillTransition(false);
|
||||
public void shrink() {
|
||||
animateWorkUtilityViews(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -310,7 +389,11 @@ public class WorkModeSwitch extends LinearLayout implements Insettable,
|
||||
public void updateStringFromCache(){
|
||||
StringCache cache = mActivityContext.getStringCache();
|
||||
if (cache != null) {
|
||||
mTextView.setText(cache.workProfilePauseButton);
|
||||
mPauseText.setText(cache.workProfilePauseButton);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldUseScheduler() {
|
||||
return Flags.workSchedulerInWorkProfile() && !mWorkSchedulerIntentAction.isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -16,22 +16,25 @@
|
||||
|
||||
package com.android.launcher3.contextualeducation;
|
||||
|
||||
import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.ResourceBasedOverride;
|
||||
import com.android.launcher3.util.SafeCloseable;
|
||||
import com.android.launcher3.dagger.LauncherAppSingleton;
|
||||
import com.android.launcher3.dagger.LauncherBaseAppComponent;
|
||||
import com.android.launcher3.util.DaggerSingletonObject;
|
||||
import com.android.systemui.contextualeducation.GestureType;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* A class to update contextual education data. It is a no-op implementation and could be
|
||||
* overridden by changing the resource value [R.string.contextual_edu_manager_class] to provide
|
||||
* a real implementation.
|
||||
* overridden through dagger modules to provide a real implementation.
|
||||
*/
|
||||
public class ContextualEduStatsManager implements ResourceBasedOverride, SafeCloseable {
|
||||
public static final MainThreadInitializedObject<ContextualEduStatsManager> INSTANCE =
|
||||
forOverride(ContextualEduStatsManager.class, R.string.contextual_edu_manager_class);
|
||||
@LauncherAppSingleton
|
||||
public class ContextualEduStatsManager {
|
||||
public static final DaggerSingletonObject<ContextualEduStatsManager> INSTANCE =
|
||||
new DaggerSingletonObject<>(LauncherBaseAppComponent::getContextualEduStatsManager);
|
||||
|
||||
@Inject
|
||||
public ContextualEduStatsManager() { }
|
||||
|
||||
|
||||
/**
|
||||
* Updates contextual education stats when a gesture is triggered
|
||||
@@ -40,8 +43,4 @@ public class ContextualEduStatsManager implements ResourceBasedOverride, SafeClo
|
||||
*/
|
||||
public void updateEduStats(boolean isTrackpadGesture, GestureType gestureType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ package com.android.launcher3.dagger;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
|
||||
import com.android.launcher3.graphics.IconShape;
|
||||
import com.android.launcher3.model.ItemInstallQueue;
|
||||
import com.android.launcher3.pm.InstallSessionHelper;
|
||||
import com.android.launcher3.util.ApiWrapper;
|
||||
import com.android.launcher3.util.DaggerSingletonTracker;
|
||||
@@ -43,9 +45,11 @@ import dagger.BindsInstance;
|
||||
public interface LauncherBaseAppComponent {
|
||||
DaggerSingletonTracker getDaggerSingletonTracker();
|
||||
ApiWrapper getApiWrapper();
|
||||
ContextualEduStatsManager getContextualEduStatsManager();
|
||||
CustomWidgetManager getCustomWidgetManager();
|
||||
IconShape getIconShape();
|
||||
InstallSessionHelper getInstallSessionHelper();
|
||||
ItemInstallQueue getItemInstallQueue();
|
||||
RefreshRateTracker getRefreshRateTracker();
|
||||
ScreenOnTracker getScreenOnTracker();
|
||||
SettingsCache getSettingsCache();
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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.icons;
|
||||
|
||||
import static android.graphics.Paint.FILTER_BITMAP_FLAG;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.Config;
|
||||
import android.graphics.BlendMode;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.ColorMatrix;
|
||||
import android.graphics.ColorMatrixColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.AdaptiveIconDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.icons.BaseIconFactory.ClippedMonoDrawable;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Utility class to generate monochrome icons version for a given drawable.
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.TIRAMISU)
|
||||
public class MonochromeIconFactory extends Drawable {
|
||||
|
||||
private final Bitmap mFlatBitmap;
|
||||
private final Canvas mFlatCanvas;
|
||||
private final Paint mCopyPaint;
|
||||
|
||||
private final Bitmap mAlphaBitmap;
|
||||
private final Canvas mAlphaCanvas;
|
||||
private final byte[] mPixels;
|
||||
|
||||
private final int mBitmapSize;
|
||||
private final int mEdgePixelLength;
|
||||
|
||||
private final Paint mDrawPaint;
|
||||
private final Rect mSrcRect;
|
||||
|
||||
MonochromeIconFactory(int iconBitmapSize) {
|
||||
float extraFactor = AdaptiveIconDrawable.getExtraInsetFraction();
|
||||
float viewPortScale = 1 / (1 + 2 * extraFactor);
|
||||
mBitmapSize = Math.round(iconBitmapSize * 2 * viewPortScale);
|
||||
mPixels = new byte[mBitmapSize * mBitmapSize];
|
||||
mEdgePixelLength = mBitmapSize * (mBitmapSize - iconBitmapSize) / 2;
|
||||
|
||||
mFlatBitmap = Bitmap.createBitmap(mBitmapSize, mBitmapSize, Config.ARGB_8888);
|
||||
mFlatCanvas = new Canvas(mFlatBitmap);
|
||||
|
||||
mAlphaBitmap = Bitmap.createBitmap(mBitmapSize, mBitmapSize, Config.ALPHA_8);
|
||||
mAlphaCanvas = new Canvas(mAlphaBitmap);
|
||||
|
||||
mDrawPaint = new Paint(FILTER_BITMAP_FLAG);
|
||||
mDrawPaint.setColor(Color.WHITE);
|
||||
mSrcRect = new Rect(0, 0, mBitmapSize, mBitmapSize);
|
||||
|
||||
mCopyPaint = new Paint(FILTER_BITMAP_FLAG);
|
||||
mCopyPaint.setBlendMode(BlendMode.SRC);
|
||||
|
||||
// Crate a color matrix which converts the icon to grayscale and then uses the average
|
||||
// of RGB components as the alpha component.
|
||||
ColorMatrix satMatrix = new ColorMatrix();
|
||||
satMatrix.setSaturation(0);
|
||||
float[] vals = satMatrix.getArray();
|
||||
vals[15] = vals[16] = vals[17] = .3333f;
|
||||
vals[18] = vals[19] = 0;
|
||||
mCopyPaint.setColorFilter(new ColorMatrixColorFilter(vals));
|
||||
}
|
||||
|
||||
private void drawDrawable(Drawable drawable) {
|
||||
if (drawable != null) {
|
||||
drawable.setBounds(0, 0, mBitmapSize, mBitmapSize);
|
||||
drawable.draw(mFlatCanvas);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a monochrome version of the provided drawable
|
||||
*/
|
||||
@WorkerThread
|
||||
public Drawable wrap(AdaptiveIconDrawable icon) {
|
||||
mFlatCanvas.drawColor(Color.BLACK);
|
||||
drawDrawable(icon.getBackground());
|
||||
drawDrawable(icon.getForeground());
|
||||
generateMono();
|
||||
return new ClippedMonoDrawable(this);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private void generateMono() {
|
||||
mAlphaCanvas.drawBitmap(mFlatBitmap, 0, 0, mCopyPaint);
|
||||
|
||||
// Scale the end points:
|
||||
ByteBuffer buffer = ByteBuffer.wrap(mPixels);
|
||||
buffer.rewind();
|
||||
mAlphaBitmap.copyPixelsToBuffer(buffer);
|
||||
|
||||
int min = 0xFF;
|
||||
int max = 0;
|
||||
for (byte b : mPixels) {
|
||||
min = Math.min(min, b & 0xFF);
|
||||
max = Math.max(max, b & 0xFF);
|
||||
}
|
||||
|
||||
if (min < max) {
|
||||
// rescale pixels to increase contrast
|
||||
float range = max - min;
|
||||
|
||||
// In order to check if the colors should be flipped, we just take the average color
|
||||
// of top and bottom edge which should correspond to be background color. If the edge
|
||||
// colors have more opacity, we flip the colors;
|
||||
int sum = 0;
|
||||
for (int i = 0; i < mEdgePixelLength; i++) {
|
||||
sum += (mPixels[i] & 0xFF);
|
||||
sum += (mPixels[mPixels.length - 1 - i] & 0xFF);
|
||||
}
|
||||
float edgeAverage = sum / (mEdgePixelLength * 2f);
|
||||
float edgeMapped = (edgeAverage - min) / range;
|
||||
boolean flipColor = edgeMapped > .5f;
|
||||
|
||||
for (int i = 0; i < mPixels.length; i++) {
|
||||
int p = mPixels[i] & 0xFF;
|
||||
int p2 = Math.round((p - min) * 0xFF / range);
|
||||
mPixels[i] = flipColor ? (byte) (255 - p2) : (byte) (p2);
|
||||
}
|
||||
buffer.rewind();
|
||||
mAlphaBitmap.copyPixelsFromBuffer(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
canvas.drawBitmap(mAlphaBitmap, mSrcRect, getBounds(), mDrawPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOpacity() {
|
||||
return PixelFormat.TRANSLUCENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int i) {
|
||||
mDrawPaint.setAlpha(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColorFilter(ColorFilter colorFilter) {
|
||||
mDrawPaint.setColorFilter(colorFilter);
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,6 @@ import android.util.Log;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.android.launcher3.Flags;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.LauncherPrefs;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
@@ -86,6 +85,9 @@ public class GridSizeMigrationDBController {
|
||||
if (needsToMigrate) {
|
||||
Log.i(TAG, "Migration is needed. destDeviceState: " + destDeviceState
|
||||
+ ", srcDeviceState: " + srcDeviceState);
|
||||
} else {
|
||||
Log.i(TAG, "Migration is not needed. destDeviceState: " + destDeviceState
|
||||
+ ", srcDeviceState: " + srcDeviceState);
|
||||
}
|
||||
return needsToMigrate;
|
||||
}
|
||||
@@ -118,21 +120,13 @@ public class GridSizeMigrationDBController {
|
||||
@NonNull DatabaseHelper target,
|
||||
@NonNull SQLiteDatabase source) {
|
||||
|
||||
Log.i("b/360462379", "Going from " + srcDeviceState.getColumns() + "x"
|
||||
+ srcDeviceState.getRows());
|
||||
Log.i("b/360462379", "Going to " + destDeviceState.getColumns() + "x"
|
||||
+ destDeviceState.getRows());
|
||||
|
||||
if (!needsToMigrate(srcDeviceState, destDeviceState)) {
|
||||
Log.i("b/360462379", "Does not need to migrate.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (LauncherPrefs.get(context).get(IS_FIRST_LOAD_AFTER_RESTORE)
|
||||
&& Flags.enableGridMigrationFix()
|
||||
&& srcDeviceState.getColumns().equals(destDeviceState.getColumns())
|
||||
&& srcDeviceState.getRows() < destDeviceState.getRows()) {
|
||||
Log.i("b/360462379", "Grid migration fix entry point.");
|
||||
// Only use this strategy when comparing the previous grid to the new grid and the
|
||||
// columns are the same and the destination has more rows
|
||||
copyTable(source, TABLE_NAME, target.getWritableDatabase(), TABLE_NAME, context);
|
||||
|
||||
@@ -339,7 +339,7 @@ class GridSizeMigrationLogic {
|
||||
srcDeviceState: DeviceGridState,
|
||||
destDeviceState: DeviceGridState,
|
||||
): Boolean {
|
||||
return (isFirstLoad && Flags.enableGridMigrationFix()) &&
|
||||
return isFirstLoad &&
|
||||
srcDeviceState.columns == destDeviceState.columns &&
|
||||
srcDeviceState.rows < destDeviceState.rows
|
||||
}
|
||||
|
||||
@@ -45,16 +45,18 @@ import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherSettings.Favorites;
|
||||
import com.android.launcher3.dagger.ApplicationContext;
|
||||
import com.android.launcher3.dagger.LauncherAppSingleton;
|
||||
import com.android.launcher3.dagger.LauncherBaseAppComponent;
|
||||
import com.android.launcher3.logging.FileLog;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.shortcuts.ShortcutKey;
|
||||
import com.android.launcher3.shortcuts.ShortcutRequest;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.DaggerSingletonObject;
|
||||
import com.android.launcher3.util.PersistedItemArray;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.launcher3.util.SafeCloseable;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
|
||||
|
||||
import java.util.HashSet;
|
||||
@@ -62,10 +64,13 @@ import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Class to maintain a queue of pending items to be added to the workspace.
|
||||
*/
|
||||
public class ItemInstallQueue implements SafeCloseable {
|
||||
@LauncherAppSingleton
|
||||
public class ItemInstallQueue {
|
||||
|
||||
private static final String LOG = "ItemInstallQueue";
|
||||
|
||||
@@ -81,9 +86,8 @@ public class ItemInstallQueue implements SafeCloseable {
|
||||
public static final int NEW_SHORTCUT_BOUNCE_DURATION = 450;
|
||||
public static final int NEW_SHORTCUT_STAGGER_DELAY = 85;
|
||||
|
||||
public static MainThreadInitializedObject<ItemInstallQueue> INSTANCE =
|
||||
new MainThreadInitializedObject<>(ItemInstallQueue::new);
|
||||
|
||||
public static DaggerSingletonObject<ItemInstallQueue> INSTANCE =
|
||||
new DaggerSingletonObject<>(LauncherBaseAppComponent::getItemInstallQueue);
|
||||
private final PersistedItemArray<PendingInstallShortcutInfo> mStorage =
|
||||
new PersistedItemArray<>(APPS_PENDING_INSTALL);
|
||||
private final Context mContext;
|
||||
@@ -95,13 +99,11 @@ public class ItemInstallQueue implements SafeCloseable {
|
||||
// Only accessed on worker thread
|
||||
private List<PendingInstallShortcutInfo> mItems;
|
||||
|
||||
private ItemInstallQueue(Context context) {
|
||||
@Inject
|
||||
public ItemInstallQueue(@ApplicationContext Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {}
|
||||
|
||||
@WorkerThread
|
||||
private void ensureQueueLoaded() {
|
||||
Preconditions.assertWorkerThread();
|
||||
|
||||
@@ -51,7 +51,6 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.Flags;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.LauncherFiles;
|
||||
@@ -124,18 +123,14 @@ public class RestoreDbTask {
|
||||
// executed again.
|
||||
LauncherPrefs.get(context).removeSync(RESTORE_DEVICE);
|
||||
|
||||
if (Flags.enableNarrowGridRestore()) {
|
||||
DeviceGridState deviceGridState = new DeviceGridState(context);
|
||||
String oldPhoneFileName = deviceGridState.getDbFile();
|
||||
List<String> previousDbs = existingDbs(context);
|
||||
removeOldDBs(context, oldPhoneFileName);
|
||||
// The idp before this contains data about the old phone, after this it becomes the idp
|
||||
// of the current phone.
|
||||
idp.reset(context);
|
||||
trySettingPreviousGridAsCurrent(context, idp, oldPhoneFileName, previousDbs);
|
||||
} else {
|
||||
idp.reinitializeAfterRestore(context);
|
||||
}
|
||||
DeviceGridState deviceGridState = new DeviceGridState(context);
|
||||
String oldPhoneFileName = deviceGridState.getDbFile();
|
||||
List<String> previousDbs = existingDbs(context);
|
||||
removeOldDBs(context, oldPhoneFileName);
|
||||
// The idp before this contains data about the old phone, after this it becomes the idp
|
||||
// of the current phone.
|
||||
idp.reset(context);
|
||||
trySettingPreviousGridAsCurrent(context, idp, oldPhoneFileName, previousDbs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -77,7 +77,6 @@ public class StateAnimationConfig {
|
||||
ANIM_WORKSPACE_PAGE_TRANSLATE_X,
|
||||
ANIM_OVERVIEW_SPLIT_SELECT_FLOATING_TASK_TRANSLATE_OFFSCREEN,
|
||||
ANIM_OVERVIEW_SPLIT_SELECT_INSTRUCTIONS_FADE,
|
||||
ANIM_ALL_APPS_BOTTOM_SHEET_FADE,
|
||||
ANIM_ALL_APPS_KEYBOARD_FADE
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@@ -101,8 +100,7 @@ public class StateAnimationConfig {
|
||||
public static final int ANIM_WORKSPACE_PAGE_TRANSLATE_X = 15;
|
||||
public static final int ANIM_OVERVIEW_SPLIT_SELECT_FLOATING_TASK_TRANSLATE_OFFSCREEN = 17;
|
||||
public static final int ANIM_OVERVIEW_SPLIT_SELECT_INSTRUCTIONS_FADE = 18;
|
||||
public static final int ANIM_ALL_APPS_BOTTOM_SHEET_FADE = 19;
|
||||
public static final int ANIM_ALL_APPS_KEYBOARD_FADE = 20;
|
||||
public static final int ANIM_ALL_APPS_KEYBOARD_FADE = 19;
|
||||
|
||||
private static final int ANIM_TYPES_COUNT = 21;
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController {
|
||||
* Applies Animation config values for transition from all apps to home.
|
||||
*/
|
||||
public static void applyAllAppsToNormalConfig(Launcher launcher, StateAnimationConfig config) {
|
||||
if (launcher.getDeviceProfile().isTablet) {
|
||||
if (launcher.getDeviceProfile().shouldShowAllAppsOnSheet()) {
|
||||
config.setInterpolator(ANIM_SCRIM_FADE,
|
||||
Interpolators.reverse(ALL_APPS_SCRIM_RESPONDER));
|
||||
config.setInterpolator(ANIM_ALL_APPS_FADE, FINAL_FRAME);
|
||||
@@ -240,7 +240,7 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController {
|
||||
*/
|
||||
public static void applyNormalToAllAppsAnimConfig(
|
||||
Launcher launcher, StateAnimationConfig config) {
|
||||
if (launcher.getDeviceProfile().isTablet) {
|
||||
if (launcher.getDeviceProfile().shouldShowAllAppsOnSheet()) {
|
||||
config.setInterpolator(ANIM_ALL_APPS_FADE, INSTANT);
|
||||
config.setInterpolator(ANIM_SCRIM_FADE, ALL_APPS_SCRIM_RESPONDER);
|
||||
if (!config.isUserControlled()) {
|
||||
|
||||
@@ -158,16 +158,16 @@ public class TaplWorkProfileTest extends AbstractLauncherUiTest<Launcher> {
|
||||
|
||||
|
||||
waitForLauncherCondition("work profile initial state check failed", launcher ->
|
||||
manager.getWorkModeSwitch() != null
|
||||
manager.getWorkUtilityView() != null
|
||||
&& manager.getCurrentState() == WorkProfileManager.STATE_ENABLED
|
||||
&& manager.getWorkModeSwitch().isEnabled(),
|
||||
&& manager.getWorkUtilityView().isEnabled(),
|
||||
LauncherInstrumentation.WAIT_TIME_MS);
|
||||
|
||||
//start work profile toggle OFF test
|
||||
executeOnLauncher(l -> {
|
||||
// Ensure updates are not deferred so notification happens when apps pause.
|
||||
l.getAppsView().getAppsStore().disableDeferUpdates(DEFER_UPDATES_TEST);
|
||||
l.getAppsView().getWorkManager().getWorkModeSwitch().performClick();
|
||||
l.getAppsView().getWorkManager().getWorkUtilityView().performClick();
|
||||
});
|
||||
|
||||
waitForLauncherCondition("Work profile toggle OFF failed", launcher -> {
|
||||
|
||||
@@ -29,6 +29,7 @@ import androidx.test.uiautomator.UiObject2;
|
||||
|
||||
import com.android.launcher3.tapl.LauncherInstrumentation.NavigationModel;
|
||||
import com.android.launcher3.tapl.LauncherInstrumentation.TrackpadGestureType;
|
||||
import com.android.launcher3.tapl.OverviewTask.TaskViewType;
|
||||
import com.android.launcher3.testing.shared.TestProtocol;
|
||||
|
||||
import java.util.List;
|
||||
@@ -121,12 +122,31 @@ public abstract class Background extends LauncherInstrumentation.VisibleContaine
|
||||
if (mLauncher.isTablet()) {
|
||||
List<UiObject2> tasks = mLauncher.getDevice().findObjects(
|
||||
TASK_SELECTOR);
|
||||
|
||||
final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
|
||||
mLauncher.assertTrue(
|
||||
"Task(s) found to the right of the swiped task",
|
||||
tasks.stream().allMatch(t ->
|
||||
t.getVisibleBounds().right < centerX
|
||||
|| t.getVisibleBounds().centerX() == centerX));
|
||||
UiObject2 centerTask = tasks.stream()
|
||||
.filter(t -> t.getVisibleCenter().x == centerX)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (centerTask != null) {
|
||||
mLauncher.assertTrue(
|
||||
"Task(s) found to the right of the swiped task",
|
||||
tasks.stream()
|
||||
.filter(t -> t != centerTask
|
||||
&& OverviewTask.getType(t)
|
||||
!= TaskViewType.DESKTOP)
|
||||
.allMatch(t -> t.getVisibleBounds().right
|
||||
< centerTask.getVisibleBounds().left));
|
||||
mLauncher.assertTrue(
|
||||
"DesktopTask(s) found to the left of the swiped task",
|
||||
tasks.stream()
|
||||
.filter(t -> t != centerTask
|
||||
&& OverviewTask.getType(t)
|
||||
== TaskViewType.DESKTOP)
|
||||
.allMatch(t -> t.getVisibleBounds().left
|
||||
> centerTask.getVisibleBounds().right));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public final class OverviewTask {
|
||||
mLauncher.assertNotNull("task must not be null", task);
|
||||
mTask = task;
|
||||
mOverview = overview;
|
||||
mType = getType();
|
||||
mType = getType(task);
|
||||
verifyActiveContainer();
|
||||
}
|
||||
|
||||
@@ -304,8 +304,12 @@ public final class OverviewTask {
|
||||
return containsContentDescription(expected, DEFAULT);
|
||||
}
|
||||
|
||||
private TaskViewType getType() {
|
||||
String resourceName = mTask.getResourceName();
|
||||
/**
|
||||
* Returns the TaskView type of the task. It will return whether the task is a single TaskView,
|
||||
* a GroupedTaskView or a DesktopTaskView.
|
||||
*/
|
||||
static TaskViewType getType(UiObject2 task) {
|
||||
String resourceName = task.getResourceName();
|
||||
if (resourceName.endsWith("task_view_grouped")) {
|
||||
return TaskViewType.GROUPED;
|
||||
} else if (resourceName.endsWith("task_view_desktop")) {
|
||||
@@ -345,7 +349,7 @@ public final class OverviewTask {
|
||||
}
|
||||
}
|
||||
|
||||
private enum TaskViewType {
|
||||
enum TaskViewType {
|
||||
SINGLE,
|
||||
GROUPED,
|
||||
DESKTOP
|
||||
|
||||
Reference in New Issue
Block a user