Snap for 7444394 from fc89cdfce4 to sc-release
Change-Id: I9457fa5068dbd5a5a423a1c88c0ca6d6824a2700
This commit is contained in:
@@ -37,5 +37,5 @@
|
||||
|
||||
<string name="wellbeing_provider_pkg" translatable="false"/>
|
||||
|
||||
<integer name="max_depth_blur_radius">150</integer>
|
||||
<integer name="max_depth_blur_radius">72</integer>
|
||||
</resources>
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.quickstep;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
|
||||
import android.view.IRecentsAnimationController;
|
||||
import android.view.SurfaceControl;
|
||||
import android.window.PictureInPictureSurfaceTransaction;
|
||||
|
||||
@@ -162,6 +163,14 @@ public class RecentsAnimationController {
|
||||
UI_HELPER_EXECUTOR.execute(() -> mController.detachNavigationBarFromApp(moveHomeToTop));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see IRecentsAnimationController#animateNavigationBarToApp(long)
|
||||
*/
|
||||
@UiThread
|
||||
public void animateNavigationBarToApp(long duration) {
|
||||
UI_HELPER_EXECUTOR.execute(() -> mController.animateNavigationBarToApp(duration));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the final surface transaction on a Task. This is used by Launcher to notify the system
|
||||
* that animating Activity to PiP has completed and the associated task surface should be
|
||||
|
||||
@@ -263,6 +263,14 @@ public final class TaskViewUtils {
|
||||
finalParams.applySurfaceParams(navBuilder.build());
|
||||
}
|
||||
});
|
||||
} else if (inLiveTileMode) {
|
||||
// There is no transition animation for app launch from recent in live tile mode so
|
||||
// we have to trigger the navigation bar animation from system here.
|
||||
final RecentsAnimationController controller =
|
||||
recentsView.getRecentsAnimationController();
|
||||
if (controller != null) {
|
||||
controller.animateNavigationBarToApp(RECENTS_LAUNCH_DURATION);
|
||||
}
|
||||
}
|
||||
topMostSimulator = tsv;
|
||||
}
|
||||
|
||||
@@ -3843,4 +3843,10 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
// The Black blending is temporary until we have the proper color token.
|
||||
return ColorUtils.blendARGB(Color.BLACK, baseColor, 0.25f);
|
||||
}
|
||||
|
||||
/** Get the RecentsAnimationController */
|
||||
@Nullable
|
||||
public RecentsAnimationController getRecentsAnimationController() {
|
||||
return mRecentsAnimationController;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,6 @@ import android.view.ViewConfiguration;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.filters.Suppress;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
import androidx.test.uiautomator.By;
|
||||
import androidx.test.uiautomator.UiDevice;
|
||||
@@ -79,10 +78,7 @@ import java.util.function.IntConsumer;
|
||||
* directly (ex: new LinearLayout)
|
||||
* Using ExtendedMockito: Mocking static methods from platform classes (loaded in zygote) makes
|
||||
* the main thread extremely slow and untestable
|
||||
*
|
||||
* Suppressed until b/141579810 is resolved
|
||||
*/
|
||||
@Suppress
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ViewInflationDuringSwipeUp extends AbstractQuickStepTest {
|
||||
@@ -188,6 +184,11 @@ public class ViewInflationDuringSwipeUp extends AbstractQuickStepTest {
|
||||
LauncherSettings.Settings.call(mResolver,
|
||||
LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG);
|
||||
LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false);
|
||||
// Make sure the widget is big enough to show a list of items
|
||||
info.minSpanX = 2;
|
||||
info.minSpanY = 2;
|
||||
info.spanX = 2;
|
||||
info.spanY = 2;
|
||||
LauncherAppWidgetInfo item = createWidgetInfo(info, getTargetContext(), true);
|
||||
|
||||
addItemToScreen(item);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<?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.
|
||||
-->
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_enabled="false">
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="@dimen/work_fab_radius" />
|
||||
<solid android:color="?android:attr/colorControlHighlight" />
|
||||
<padding android:left="@dimen/work_fab_radius" android:right="@dimen/work_fab_radius" />
|
||||
</shape>
|
||||
</item>
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="@dimen/work_fab_radius" />
|
||||
<solid android:color="?android:attr/colorAccent" />
|
||||
<padding android:left="@dimen/work_fab_radius" android:right="@dimen/work_fab_radius" />
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.launcher3.allapps.WorkModeSwitch
|
||||
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:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:drawableTint="@android:color/white"
|
||||
android:textColor="@android:color/white"
|
||||
android:background="@drawable/work_apps_toggle_background"
|
||||
android:drawablePadding="16dp"
|
||||
android:drawableStart="@drawable/ic_corp_off"
|
||||
android:elevation="10dp"
|
||||
android:layout_marginBottom="@dimen/work_fab_margin"
|
||||
android:layout_marginEnd="@dimen/work_fab_margin"
|
||||
android:text="@string/work_apps_pause_btn_text" />
|
||||
@@ -1,5 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2017 The Android Open Source Project
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -13,8 +12,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.launcher3.allapps.WorkModeSwitch
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<com.android.launcher3.allapps.WorkModeSwitch xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/PrimaryHeadline"
|
||||
@@ -35,5 +33,4 @@
|
||||
android:paddingBottom="@dimen/work_profile_footer_padding"
|
||||
android:paddingLeft="@dimen/work_profile_footer_padding"
|
||||
android:paddingRight="@dimen/work_profile_footer_padding"
|
||||
android:paddingTop="@dimen/work_profile_footer_padding"
|
||||
/>
|
||||
android:paddingTop="@dimen/work_profile_footer_padding" />
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2020 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.launcher3.views.WorkEduView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:gravity="bottom"
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="32dp"
|
||||
android:background="@drawable/bottom_sheet_top_border"
|
||||
android:backgroundTint="?attr/eduHalfSheetBGColor" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/view_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/eduHalfSheetBGColor"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@dimen/bottom_sheet_edu_padding"
|
||||
android:paddingRight="@dimen/bottom_sheet_edu_padding">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/content_text"
|
||||
style="@style/TextHeadline"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="48dp"
|
||||
android:layout_marginBottom="48dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/work_profile_edu_personal_apps"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/proceed"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="end"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:gravity="center"
|
||||
android:text="@string/work_profile_edu_next"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white" />
|
||||
</LinearLayout>
|
||||
</com.android.launcher3.views.WorkEduView>
|
||||
@@ -37,4 +37,6 @@
|
||||
|
||||
<color name="wallpaper_popup_scrim">@android:color/system_neutral1_900</color>
|
||||
|
||||
<color name="folder_dot_color">@android:color/system_accent2_50</color>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -59,6 +59,8 @@
|
||||
<color name="folder_hint_text_color_light">#FFF</color>
|
||||
<color name="folder_hint_text_color_dark">#FF000000</color>
|
||||
|
||||
<color name="folder_dot_color">?attr/colorPrimary</color>
|
||||
|
||||
<color name="text_color_primary_dark">#FFFFFFFF</color>
|
||||
<color name="text_color_secondary_dark">#FFFFFFFF</color>
|
||||
<color name="text_color_tertiary_dark">#CCFFFFFF</color>
|
||||
|
||||
@@ -115,6 +115,10 @@
|
||||
|
||||
<dimen name="all_apps_divider_margin_vertical">8dp</dimen>
|
||||
|
||||
<!-- Floating action button inside work tab to toggle work profile -->
|
||||
<dimen name="work_fab_height">48dp</dimen>
|
||||
<dimen name="work_fab_radius">24dp</dimen>
|
||||
<dimen name="work_fab_margin">18dp</dimen>
|
||||
<dimen name="work_profile_footer_padding">20dp</dimen>
|
||||
<dimen name="work_profile_footer_text_size">16sp</dimen>
|
||||
|
||||
|
||||
@@ -389,27 +389,24 @@
|
||||
<string name="work_profile_edu_accept">Got it</string>
|
||||
|
||||
<!--- heading shown when user opens work apps tab while work apps are paused -->
|
||||
<string name="work_apps_paused_title">Work profile is paused</string>
|
||||
<string name="work_apps_paused_title">Work apps are off</string>
|
||||
<!--- body shown when user opens work apps tab while work apps are paused -->
|
||||
<string name="work_apps_paused_body">Work apps can’t send you notifications, use your battery, or access your location</string>
|
||||
<string name="work_apps_paused_body">Your work apps can’t send you notifications, use your battery, or access your location</string>
|
||||
<!-- content description for paused work apps list -->
|
||||
<string name="work_apps_paused_content_description">Work profile is paused. Work apps can’t send you notifications, use your battery, or access your location</string>
|
||||
<string name="work_apps_paused_content_description">Work apps are off. Your work apps can’t send you notifications, use your battery, or access your location</string>
|
||||
<!-- string shown in educational banner about work profile -->
|
||||
<string name="work_apps_paused_edu_banner">Work apps are badged and visible to your IT admin</string>
|
||||
<!-- button string shown to dismiss work tab education -->
|
||||
<string name="work_apps_paused_edu_accept">Got it</string>
|
||||
|
||||
<!-- button string shown pause work profile -->
|
||||
<string name="work_apps_pause_btn_text">Pause work apps</string>
|
||||
<string name="work_apps_pause_btn_text">Turn off work apps</string>
|
||||
<!-- button string shown enable work profile -->
|
||||
<string name="work_apps_enable_btn_text">Turn on</string>
|
||||
<string name="work_apps_enable_btn_text">Turn on work apps</string>
|
||||
|
||||
<!-- A hint shown in launcher settings develop options filter box -->
|
||||
<string name="developer_options_filter_hint">Filter</string>
|
||||
|
||||
<!-- A tip shown pointing at work toggle -->
|
||||
<string name="work_switch_tip">Pause work apps and notifications</string>
|
||||
|
||||
<!-- Failed action error message: e.g. Failed: Pause -->
|
||||
<string name="remote_action_failed">Failed: <xliff:g id="what" example="Pause">%1$s</xliff:g></string>
|
||||
</resources>
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
<item name="workspaceKeyShadowColor">#89000000</item>
|
||||
<item name="workspaceStatusBarScrim">@drawable/workspace_bg</item>
|
||||
<item name="widgetsTheme">@style/WidgetContainerTheme</item>
|
||||
<item name="folderDotColor">?android:attr/colorPrimary</item>
|
||||
<item name="folderDotColor">@color/folder_dot_color</item>
|
||||
<item name="folderFillColor">?android:attr/colorBackgroundFloating</item>
|
||||
<item name="folderIconBorderColor">?android:attr/colorPrimary</item>
|
||||
<item name="folderTextColor">?android:attr/textColorPrimary</item>
|
||||
@@ -86,7 +86,7 @@
|
||||
<item name="workspaceKeyShadowColor">@android:color/transparent</item>
|
||||
<item name="isWorkspaceDarkText">true</item>
|
||||
<item name="workspaceStatusBarScrim">@null</item>
|
||||
<item name="folderDotColor">#FF464646</item>
|
||||
<item name="folderDotColor">@color/folder_dot_color</item>
|
||||
<item name="folderFillColor">?android:attr/colorBackgroundFloating</item>
|
||||
<item name="folderIconBorderColor">#FF80868B</item>
|
||||
<item name="folderTextColor">?attr/workspaceTextColor</item>
|
||||
@@ -108,7 +108,7 @@
|
||||
<item name="popupColorSecondary">@color/popup_color_secondary_dark</item>
|
||||
<item name="popupColorTertiary">@color/popup_color_tertiary_dark</item>
|
||||
<item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
|
||||
<item name="folderDotColor">?android:attr/colorPrimary</item>
|
||||
<item name="folderDotColor">@color/folder_dot_color</item>
|
||||
<item name="folderFillColor">?android:attr/colorBackgroundFloating</item>
|
||||
<item name="folderIconBorderColor">?android:attr/colorPrimary</item>
|
||||
<item name="folderTextColor">?android:attr/textColorPrimary</item>
|
||||
|
||||
@@ -4,7 +4,6 @@ import static android.appwidget.AppWidgetHostView.getDefaultPaddingForWidget;
|
||||
|
||||
import static com.android.launcher3.LauncherAnimUtils.LAYOUT_HEIGHT;
|
||||
import static com.android.launcher3.LauncherAnimUtils.LAYOUT_WIDTH;
|
||||
import static com.android.launcher3.Utilities.ATLEAST_S;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_RESIZE_COMPLETED;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_RESIZE_STARTED;
|
||||
import static com.android.launcher3.views.BaseDragLayer.LAYOUT_X;
|
||||
@@ -13,18 +12,12 @@ import static com.android.launcher3.views.BaseDragLayer.LAYOUT_Y;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.appwidget.AppWidgetHostView;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SizeF;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
@@ -39,10 +32,10 @@ import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.util.PendingRequestArgs;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetHostView;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
|
||||
import com.android.launcher3.widget.util.WidgetSizes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AppWidgetResizeFrame extends AbstractFloatingView implements View.OnKeyListener {
|
||||
private static final int SNAP_DURATION = 150;
|
||||
@@ -415,90 +408,12 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O
|
||||
mRunningHInc += hSpanDelta;
|
||||
|
||||
if (!onDismiss) {
|
||||
updateWidgetSizeRanges(mWidgetView, mLauncher, spanX, spanY);
|
||||
WidgetSizes.updateWidgetSizeRanges(mWidgetView, mLauncher, spanX, spanY);
|
||||
}
|
||||
}
|
||||
mWidgetView.requestLayout();
|
||||
}
|
||||
|
||||
public static void updateWidgetSizeRanges(
|
||||
AppWidgetHostView widgetView, Context context, int spanX, int spanY) {
|
||||
List<SizeF> sizes = getWidgetSizes(context, spanX, spanY);
|
||||
if (ATLEAST_S) {
|
||||
widgetView.updateAppWidgetSize(new Bundle(), sizes);
|
||||
} else {
|
||||
Rect bounds = getMinMaxSizes(sizes);
|
||||
widgetView.updateAppWidgetSize(new Bundle(), bounds.left, bounds.top, bounds.right,
|
||||
bounds.bottom);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the list of sizes for a widget of given span, in dp. */
|
||||
public static ArrayList<SizeF> getWidgetSizes(Context context, int spanX, int spanY) {
|
||||
ArrayList<SizeF> sizes = new ArrayList<>(2);
|
||||
final float density = context.getResources().getDisplayMetrics().density;
|
||||
Point cellSize = new Point();
|
||||
|
||||
for (DeviceProfile profile : LauncherAppState.getIDP(context).supportedProfiles) {
|
||||
final float hBorderSpacing = (spanX - 1) * profile.cellLayoutBorderSpacingPx;
|
||||
final float vBorderSpacing = (spanY - 1) * profile.cellLayoutBorderSpacingPx;
|
||||
profile.getCellSize(cellSize);
|
||||
sizes.add(new SizeF(
|
||||
((spanX * cellSize.x) + hBorderSpacing) / density,
|
||||
((spanY * cellSize.y) + vBorderSpacing) / density));
|
||||
}
|
||||
return sizes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bundle to be used as the default options for a widget with provided size
|
||||
*/
|
||||
public static Bundle getWidgetSizeOptions(
|
||||
Context context, ComponentName provider, int spanX, int spanY) {
|
||||
ArrayList<SizeF> sizes = getWidgetSizes(context, spanX, spanY);
|
||||
Rect padding = getDefaultPaddingForWidget(context, provider, null);
|
||||
float density = context.getResources().getDisplayMetrics().density;
|
||||
float xPaddingDips = (padding.left + padding.right) / density;
|
||||
float yPaddingDips = (padding.top + padding.bottom) / density;
|
||||
|
||||
ArrayList<SizeF> paddedSizes = sizes.stream()
|
||||
.map(size -> new SizeF(
|
||||
Math.max(0.f, size.getWidth() - xPaddingDips),
|
||||
Math.max(0.f, size.getHeight() - yPaddingDips)))
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
|
||||
Rect rect = AppWidgetResizeFrame.getMinMaxSizes(paddedSizes);
|
||||
Bundle options = new Bundle();
|
||||
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, rect.left);
|
||||
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, rect.top);
|
||||
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, rect.right);
|
||||
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, rect.bottom);
|
||||
options.putParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES, paddedSizes);
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the min and max widths and heights given a list of sizes, in dp.
|
||||
*
|
||||
* @param sizes List of sizes to get the min/max from.
|
||||
* @return A rectangle with the left (resp. top) is used for the min width (resp. height) and
|
||||
* the right (resp. bottom) for the max. The returned rectangle is set with 0s if the list is
|
||||
* empty.
|
||||
*/
|
||||
private static Rect getMinMaxSizes(List<SizeF> sizes) {
|
||||
if (sizes.isEmpty()) {
|
||||
return new Rect();
|
||||
} else {
|
||||
SizeF first = sizes.get(0);
|
||||
Rect result = new Rect((int) first.getWidth(), (int) first.getHeight(),
|
||||
(int) first.getWidth(), (int) first.getHeight());
|
||||
for (int i = 1; i < sizes.size(); i++) {
|
||||
result.union((int) sizes.get(i).getWidth(), (int) sizes.get(i).getHeight());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
|
||||
@@ -1076,9 +1076,10 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
getRotationHelper().setCurrentStateRequest(REQUEST_NONE);
|
||||
}
|
||||
|
||||
if (mPrevLauncherState != state && !ALL_APPS.equals(state)
|
||||
if (ALL_APPS.equals(mPrevLauncherState) && !ALL_APPS.equals(state)
|
||||
// Making sure mAllAppsSessionLogId is not null to avoid double logging.
|
||||
&& mAllAppsSessionLogId != null) {
|
||||
getAppsView().getSearchUiManager().resetSearch();
|
||||
getStatsLogManager().logger().log(LAUNCHER_ALLAPPS_EXIT);
|
||||
mAllAppsSessionLogId = null;
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@ import android.os.AsyncTask;
|
||||
import android.os.CancellationSignal;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Log;
|
||||
import android.util.LongSparseArray;
|
||||
import android.util.Pair;
|
||||
import android.util.Size;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
@@ -50,6 +50,7 @@ import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
|
||||
import com.android.launcher3.widget.WidgetCell;
|
||||
import com.android.launcher3.widget.WidgetManagerHelper;
|
||||
import com.android.launcher3.widget.util.WidgetSizes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -79,9 +80,6 @@ public class WidgetPreviewLoader {
|
||||
private final UserCache mUserCache;
|
||||
private final CacheDb mDb;
|
||||
|
||||
private final UserHandle mMyUser = Process.myUserHandle();
|
||||
private final ArrayMap<UserHandle, Bitmap> mUserBadges = new ArrayMap<>();
|
||||
|
||||
public WidgetPreviewLoader(Context context, IconCache iconCache) {
|
||||
mContext = context;
|
||||
mIconCache = iconCache;
|
||||
@@ -366,9 +364,9 @@ public class WidgetPreviewLoader {
|
||||
previewHeight = drawable.getIntrinsicHeight();
|
||||
} else {
|
||||
DeviceProfile dp = launcher.getDeviceProfile();
|
||||
int tileSize = Math.min(dp.cellWidthPx, dp.cellHeightPx);
|
||||
previewWidth = tileSize * spanX;
|
||||
previewHeight = tileSize * spanY;
|
||||
Size widgetSize = WidgetSizes.getWidgetSizePx(dp, spanX, spanY);
|
||||
previewWidth = widgetSize.getWidth();
|
||||
previewHeight = widgetSize.getHeight();
|
||||
}
|
||||
|
||||
// Scale to fit width only - let the widget preview be clipped in the
|
||||
|
||||
@@ -114,6 +114,7 @@ import com.android.launcher3.widget.PendingAddWidgetInfo;
|
||||
import com.android.launcher3.widget.PendingAppWidgetHostView;
|
||||
import com.android.launcher3.widget.WidgetManagerHelper;
|
||||
import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
|
||||
import com.android.launcher3.widget.util.WidgetSizes;
|
||||
import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -1854,7 +1855,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
item.spanX = resultSpan[0];
|
||||
item.spanY = resultSpan[1];
|
||||
AppWidgetHostView awhv = (AppWidgetHostView) cell;
|
||||
AppWidgetResizeFrame.updateWidgetSizeRanges(awhv, mLauncher, resultSpan[0],
|
||||
WidgetSizes.updateWidgetSizeRanges(awhv, mLauncher, resultSpan[0],
|
||||
resultSpan[1]);
|
||||
}
|
||||
|
||||
@@ -2528,8 +2529,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
||||
((PendingAddWidgetInfo) pendingInfo).boundWidget : null;
|
||||
|
||||
if (finalView != null && updateWidgetSize) {
|
||||
AppWidgetResizeFrame.updateWidgetSizeRanges(finalView, mLauncher, item.spanX,
|
||||
item.spanY);
|
||||
WidgetSizes.updateWidgetSizeRanges(finalView, mLauncher, item.spanX, item.spanY);
|
||||
}
|
||||
|
||||
int animationStyle = ANIMATE_INTO_POSITION_AND_DISAPPEAR;
|
||||
|
||||
@@ -21,7 +21,6 @@ import android.view.View.AccessibilityDelegate;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
|
||||
|
||||
import com.android.launcher3.AppWidgetResizeFrame;
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
import com.android.launcher3.ButtonDropTarget;
|
||||
import com.android.launcher3.CellLayout;
|
||||
@@ -51,6 +50,7 @@ import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.views.OptionsPopupView;
|
||||
import com.android.launcher3.views.OptionsPopupView.OptionItem;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetHostView;
|
||||
import com.android.launcher3.widget.util.WidgetSizes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -367,7 +367,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
|
||||
}
|
||||
|
||||
layout.markCellsAsOccupiedForView(host);
|
||||
AppWidgetResizeFrame.updateWidgetSizeRanges(((LauncherAppWidgetHostView) host), mLauncher,
|
||||
WidgetSizes.updateWidgetSizeRanges(((LauncherAppWidgetHostView) host), mLauncher,
|
||||
info.spanX, info.spanY);
|
||||
host.requestLayout();
|
||||
mLauncher.getModelWriter().updateItemInDatabase(info);
|
||||
|
||||
@@ -228,7 +228,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
}
|
||||
|
||||
private void resetWorkProfile() {
|
||||
mWorkModeSwitch.update(!mAllAppsStore.hasModelFlag(FLAG_QUIET_MODE_ENABLED));
|
||||
mWorkModeSwitch.updateCurrentState(!mAllAppsStore.hasModelFlag(FLAG_QUIET_MODE_ENABLED));
|
||||
mAH[AdapterHolder.WORK].setupOverlay();
|
||||
mAH[AdapterHolder.WORK].applyPadding();
|
||||
}
|
||||
@@ -482,7 +482,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
||||
private void setupWorkToggle() {
|
||||
if (Utilities.ATLEAST_P) {
|
||||
mWorkModeSwitch = (WorkModeSwitch) mLauncher.getLayoutInflater().inflate(
|
||||
R.layout.work_mode_switch, this, false);
|
||||
R.layout.work_mode_fab, this, false);
|
||||
this.addView(mWorkModeSwitch);
|
||||
mWorkModeSwitch.setInsets(mInsets);
|
||||
mWorkModeSwitch.post(this::resetWorkProfile);
|
||||
|
||||
@@ -25,7 +25,6 @@ import android.view.MotionEvent;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.statemanager.StateManager.StateListener;
|
||||
import com.android.launcher3.views.WorkEduView;
|
||||
|
||||
/**
|
||||
* AllAppsContainerView with launcher specific callbacks
|
||||
@@ -88,13 +87,6 @@ public class LauncherAllAppsContainerView extends AllAppsContainerView {
|
||||
@Override
|
||||
public void onActivePageChanged(int currentActivePage) {
|
||||
super.onActivePageChanged(currentActivePage);
|
||||
if (mUsingTabs) {
|
||||
if (currentActivePage == AdapterHolder.WORK) {
|
||||
WorkEduView.showWorkEduIfNeeded(mLauncher);
|
||||
} else {
|
||||
mWorkTabListener = WorkEduView.showEduFlowIfNeeded(mLauncher, mWorkTabListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,108 +15,57 @@
|
||||
*/
|
||||
package com.android.launcher3.allapps;
|
||||
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Rect;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.widget.Switch;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.pm.UserCache;
|
||||
import com.android.launcher3.views.ArrowTipView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* Work profile toggle switch shown at the bottom of AllApps work tab
|
||||
*/
|
||||
public class WorkModeSwitch extends Switch implements Insettable {
|
||||
|
||||
private static final int WORK_TIP_THRESHOLD = 2;
|
||||
public static final String KEY_WORK_TIP_COUNTER = "worked_tip_counter";
|
||||
public class WorkModeSwitch extends Button implements Insettable, View.OnClickListener {
|
||||
|
||||
private Rect mInsets = new Rect();
|
||||
|
||||
private final float[] mTouch = new float[2];
|
||||
private int mTouchSlop;
|
||||
private boolean mWorkEnabled;
|
||||
|
||||
public WorkModeSwitch(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
this(context, null, 0);
|
||||
}
|
||||
|
||||
public WorkModeSwitch(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public WorkModeSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
ViewConfiguration viewConfiguration = ViewConfiguration.get(getContext());
|
||||
mTouchSlop = viewConfiguration.getScaledTouchSlop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChecked(boolean checked) { }
|
||||
|
||||
@Override
|
||||
public void toggle() {
|
||||
// don't show tip if user uses toggle
|
||||
Utilities.getPrefs(getContext()).edit().putInt(KEY_WORK_TIP_COUNTER, -1).apply();
|
||||
trySetQuietModeEnabledToAllProfilesAsync(isChecked());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the enabled or disabled state of the button
|
||||
* @param isChecked
|
||||
*/
|
||||
public void update(boolean isChecked) {
|
||||
super.setChecked(isChecked);
|
||||
setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||
isChecked ? R.drawable.ic_corp : R.drawable.ic_corp_off, 0, 0, 0);
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
||||
mTouch[0] = ev.getX();
|
||||
mTouch[1] = ev.getY();
|
||||
} else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
|
||||
if (Math.abs(mTouch[0] - ev.getX()) > mTouchSlop
|
||||
|| Math.abs(mTouch[1] - ev.getY()) > mTouchSlop) {
|
||||
int action = ev.getAction();
|
||||
ev.setAction(MotionEvent.ACTION_CANCEL);
|
||||
super.onTouchEvent(ev);
|
||||
ev.setAction(action);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return super.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
private void trySetQuietModeEnabledToAllProfilesAsync(boolean enabled) {
|
||||
new SetQuietModeEnabledAsyncTask(enabled, new WeakReference<>(this)).execute();
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInsets(Rect insets) {
|
||||
int bottomInset = insets.bottom - mInsets.bottom;
|
||||
mInsets.set(insets);
|
||||
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
|
||||
getPaddingBottom() + bottomInset);
|
||||
ViewGroup.MarginLayoutParams marginLayoutParams =
|
||||
(ViewGroup.MarginLayoutParams) getLayoutParams();
|
||||
if (marginLayoutParams != null) {
|
||||
marginLayoutParams.bottomMargin = bottomInset + marginLayoutParams.bottomMargin;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,78 +74,41 @@ public class WorkModeSwitch extends Switch implements Insettable {
|
||||
public void setWorkTabVisible(boolean workTabVisible) {
|
||||
clearAnimation();
|
||||
if (workTabVisible) {
|
||||
setEnabled(true);
|
||||
setVisibility(VISIBLE);
|
||||
setAlpha(0);
|
||||
animate().alpha(1).start();
|
||||
showTipIfNeeded();
|
||||
} else {
|
||||
animate().alpha(0).withEndAction(() -> this.setVisibility(GONE)).start();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class SetQuietModeEnabledAsyncTask
|
||||
extends AsyncTask<Void, Void, Boolean> {
|
||||
|
||||
private final boolean enabled;
|
||||
private final WeakReference<WorkModeSwitch> switchWeakReference;
|
||||
|
||||
SetQuietModeEnabledAsyncTask(boolean enabled,
|
||||
WeakReference<WorkModeSwitch> switchWeakReference) {
|
||||
this.enabled = enabled;
|
||||
this.switchWeakReference = switchWeakReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
WorkModeSwitch workModeSwitch = switchWeakReference.get();
|
||||
if (workModeSwitch != null) {
|
||||
workModeSwitch.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
WorkModeSwitch workModeSwitch = switchWeakReference.get();
|
||||
if (workModeSwitch == null || !Utilities.ATLEAST_P) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Context context = workModeSwitch.getContext();
|
||||
UserManager userManager = context.getSystemService(UserManager.class);
|
||||
boolean showConfirm = false;
|
||||
for (UserHandle userProfile : UserCache.INSTANCE.get(context).getUserProfiles()) {
|
||||
if (Process.myUserHandle().equals(userProfile)) {
|
||||
continue;
|
||||
}
|
||||
showConfirm |= !userManager.requestQuietModeEnabled(enabled, userProfile);
|
||||
}
|
||||
return showConfirm;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean showConfirm) {
|
||||
if (showConfirm) {
|
||||
WorkModeSwitch workModeSwitch = switchWeakReference.get();
|
||||
if (workModeSwitch != null) {
|
||||
workModeSwitch.setEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
setEnabled(false);
|
||||
UI_HELPER_EXECUTOR.post(() -> setToState(!mWorkEnabled));
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a work tip on the Nth work tab open
|
||||
* Sets the enabled or disabled state of the button
|
||||
*/
|
||||
public void showTipIfNeeded() {
|
||||
Context context = getContext();
|
||||
SharedPreferences prefs = Utilities.getPrefs(context);
|
||||
int tipCounter = prefs.getInt(KEY_WORK_TIP_COUNTER, WORK_TIP_THRESHOLD);
|
||||
if (tipCounter < 0) return;
|
||||
if (tipCounter == 0) {
|
||||
new ArrowTipView(context)
|
||||
.show(context.getString(R.string.work_switch_tip), getTop());
|
||||
public void updateCurrentState(boolean active) {
|
||||
mWorkEnabled = active;
|
||||
setEnabled(true);
|
||||
setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||
active ? R.drawable.ic_corp_off : R.drawable.ic_corp, 0, 0, 0);
|
||||
setText(active ? R.string.work_apps_pause_btn_text : R.string.work_apps_enable_btn_text);
|
||||
}
|
||||
|
||||
protected Boolean setToState(boolean toState) {
|
||||
UserManager userManager = getContext().getSystemService(UserManager.class);
|
||||
boolean showConfirm = false;
|
||||
for (UserHandle userProfile : UserCache.INSTANCE.get(getContext()).getUserProfiles()) {
|
||||
if (Process.myUserHandle().equals(userProfile)) {
|
||||
continue;
|
||||
}
|
||||
showConfirm |= !userManager.requestQuietModeEnabled(!toState, userProfile);
|
||||
}
|
||||
prefs.edit().putInt(KEY_WORK_TIP_COUNTER, tipCounter - 1).apply();
|
||||
return showConfirm;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ public final class FeatureFlags {
|
||||
|
||||
// Keep as DeviceFlag to allow remote disable in emergency.
|
||||
public static final BooleanFlag ENABLE_SUGGESTED_ACTIONS_OVERVIEW = new DeviceFlag(
|
||||
"ENABLE_SUGGESTED_ACTIONS_OVERVIEW", true, "Show chip hints on the overview screen");
|
||||
"ENABLE_SUGGESTED_ACTIONS_OVERVIEW", false, "Show chip hints on the overview screen");
|
||||
|
||||
|
||||
public static final BooleanFlag ENABLE_DEVICE_SEARCH = new DeviceFlag(
|
||||
|
||||
@@ -26,13 +26,13 @@ import android.os.Process;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.AppWidgetResizeFrame;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.logger.LauncherAtom;
|
||||
import com.android.launcher3.util.ContentWriter;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetHostView;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
|
||||
import com.android.launcher3.widget.util.WidgetSizes;
|
||||
|
||||
/**
|
||||
* Represents a widget (either instantiated or about to be) in the Launcher.
|
||||
@@ -196,7 +196,7 @@ public class LauncherAppWidgetInfo extends ItemInfo {
|
||||
*/
|
||||
public void onBindAppWidget(Launcher launcher, AppWidgetHostView hostView) {
|
||||
if (!mHasNotifiedInitialWidgetSizeChanged) {
|
||||
AppWidgetResizeFrame.updateWidgetSizeRanges(hostView, launcher, spanX, spanY);
|
||||
WidgetSizes.updateWidgetSizeRanges(hostView, launcher, spanX, spanY);
|
||||
mHasNotifiedInitialWidgetSizeChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@ import static android.appwidget.AppWidgetManager.ACTION_APPWIDGET_BIND;
|
||||
import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID;
|
||||
import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_PROVIDER;
|
||||
|
||||
import static com.android.launcher3.AppWidgetResizeFrame.getWidgetSizeOptions;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.app.SearchManager;
|
||||
@@ -49,6 +47,7 @@ import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.graphics.FragmentWithPreview;
|
||||
import com.android.launcher3.widget.util.WidgetSizes;
|
||||
|
||||
/**
|
||||
* A frame layout which contains a QSB. This internally uses fragment to bind the view, which
|
||||
@@ -292,7 +291,8 @@ public class QsbContainerView extends FrameLayout {
|
||||
|
||||
protected Bundle createBindOptions() {
|
||||
InvariantDeviceProfile idp = LauncherAppState.getIDP(getContext());
|
||||
return getWidgetSizeOptions(getContext(), mWidgetInfo.provider, idp.numColumns, 1);
|
||||
return WidgetSizes.getWidgetSizeOptions(getContext(), mWidgetInfo.provider,
|
||||
idp.numColumns, 1);
|
||||
}
|
||||
|
||||
protected View getDefaultView(ViewGroup container, boolean showSetupIcon) {
|
||||
|
||||
@@ -1,230 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.views;
|
||||
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.allapps.AllAppsContainerView;
|
||||
import com.android.launcher3.allapps.AllAppsPagedView;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.statemanager.StateManager.StateListener;
|
||||
|
||||
/**
|
||||
* On boarding flow for users right after setting up work profile
|
||||
*/
|
||||
public class WorkEduView extends AbstractSlideInView<Launcher>
|
||||
implements Insettable, StateListener<LauncherState> {
|
||||
|
||||
private static final int DEFAULT_CLOSE_DURATION = 200;
|
||||
public static final String KEY_WORK_EDU_STEP = "showed_work_profile_edu";
|
||||
public static final String KEY_LEGACY_WORK_EDU_SEEN = "showed_bottom_user_education";
|
||||
|
||||
private static final int WORK_EDU_NOT_STARTED = 0;
|
||||
private static final int WORK_EDU_PERSONAL_APPS = 1;
|
||||
private static final int WORK_EDU_WORK_APPS = 2;
|
||||
|
||||
protected static final int FINAL_SCRIM_BG_COLOR = 0x88000000;
|
||||
|
||||
|
||||
private Rect mInsets = new Rect();
|
||||
private View mViewWrapper;
|
||||
private Button mProceedButton;
|
||||
private TextView mContentText;
|
||||
|
||||
private int mNextWorkEduStep = WORK_EDU_PERSONAL_APPS;
|
||||
|
||||
|
||||
public WorkEduView(Context context, AttributeSet attr) {
|
||||
this(context, attr, 0);
|
||||
}
|
||||
|
||||
public WorkEduView(Context context, AttributeSet attrs,
|
||||
int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mContent = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleClose(boolean animate) {
|
||||
mActivityContext.getSharedPrefs().edit()
|
||||
.putInt(KEY_WORK_EDU_STEP, mNextWorkEduStep).apply();
|
||||
handleClose(true, DEFAULT_CLOSE_DURATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCloseComplete() {
|
||||
super.onCloseComplete();
|
||||
mActivityContext.getStateManager().removeStateListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isOfType(int type) {
|
||||
return (type & TYPE_ON_BOARD_POPUP) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mViewWrapper = findViewById(R.id.view_wrapper);
|
||||
mProceedButton = findViewById(R.id.proceed);
|
||||
mContentText = findViewById(R.id.content_text);
|
||||
|
||||
// make sure layout does not shrink when we change the text
|
||||
mContentText.post(() -> mContentText.setMinLines(mContentText.getLineCount()));
|
||||
|
||||
mProceedButton.setOnClickListener(view -> {
|
||||
if (getAllAppsPagedView() != null) {
|
||||
getAllAppsPagedView().snapToPage(AllAppsContainerView.AdapterHolder.WORK);
|
||||
}
|
||||
goToWorkTab(true);
|
||||
});
|
||||
}
|
||||
|
||||
private void goToWorkTab(boolean animate) {
|
||||
mProceedButton.setText(R.string.work_profile_edu_accept);
|
||||
if (animate) {
|
||||
ObjectAnimator animator = ObjectAnimator.ofFloat(mContentText, ALPHA, 0);
|
||||
animator.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
mContentText.setText(
|
||||
mActivityContext.getString(R.string.work_profile_edu_work_apps));
|
||||
ObjectAnimator.ofFloat(mContentText, ALPHA, 1).start();
|
||||
}
|
||||
});
|
||||
animator.start();
|
||||
} else {
|
||||
mContentText.setText(mActivityContext.getString(R.string.work_profile_edu_work_apps));
|
||||
}
|
||||
mNextWorkEduStep = WORK_EDU_WORK_APPS;
|
||||
mProceedButton.setOnClickListener(v -> handleClose(true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInsets(Rect insets) {
|
||||
int leftInset = insets.left - mInsets.left;
|
||||
int rightInset = insets.right - mInsets.right;
|
||||
int bottomInset = insets.bottom - mInsets.bottom;
|
||||
mInsets.set(insets);
|
||||
setPadding(leftInset, getPaddingTop(), rightInset, 0);
|
||||
mViewWrapper.setPaddingRelative(mViewWrapper.getPaddingStart(),
|
||||
mViewWrapper.getPaddingTop(), mViewWrapper.getPaddingEnd(), bottomInset);
|
||||
}
|
||||
|
||||
private void show() {
|
||||
attachToContainer();
|
||||
animateOpen();
|
||||
mActivityContext.getStateManager().addStateListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getScrimColor(Context context) {
|
||||
return FINAL_SCRIM_BG_COLOR;
|
||||
}
|
||||
|
||||
private void goToFirstPage() {
|
||||
if (getAllAppsPagedView() != null) {
|
||||
getAllAppsPagedView().snapToPageImmediately(AllAppsContainerView.AdapterHolder.MAIN);
|
||||
}
|
||||
}
|
||||
|
||||
private void animateOpen() {
|
||||
if (mIsOpen || mOpenCloseAnimator.isRunning()) {
|
||||
return;
|
||||
}
|
||||
mIsOpen = true;
|
||||
mOpenCloseAnimator.setValues(
|
||||
PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
|
||||
mOpenCloseAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
|
||||
mOpenCloseAnimator.start();
|
||||
}
|
||||
|
||||
private AllAppsPagedView getAllAppsPagedView() {
|
||||
View v = mActivityContext.getAppsView().getContentView();
|
||||
return (v instanceof AllAppsPagedView) ? (AllAppsPagedView) v : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if user has not seen onboarding UI yet and shows it when user navigates to all apps
|
||||
*/
|
||||
public static StateListener<LauncherState> showEduFlowIfNeeded(Launcher launcher,
|
||||
@Nullable StateListener<LauncherState> oldListener) {
|
||||
if (oldListener != null) {
|
||||
launcher.getStateManager().removeStateListener(oldListener);
|
||||
}
|
||||
if (hasSeenLegacyEdu(launcher) || launcher.getSharedPrefs().getInt(KEY_WORK_EDU_STEP,
|
||||
WORK_EDU_NOT_STARTED) != WORK_EDU_NOT_STARTED) {
|
||||
return null;
|
||||
}
|
||||
|
||||
StateListener<LauncherState> listener = new StateListener<LauncherState>() {
|
||||
@Override
|
||||
public void onStateTransitionComplete(LauncherState finalState) {
|
||||
if (finalState != LauncherState.ALL_APPS) return;
|
||||
LayoutInflater layoutInflater = LayoutInflater.from(launcher);
|
||||
WorkEduView v = (WorkEduView) layoutInflater.inflate(
|
||||
R.layout.work_profile_edu, launcher.getDragLayer(),
|
||||
false);
|
||||
v.show();
|
||||
v.goToFirstPage();
|
||||
launcher.getStateManager().removeStateListener(this);
|
||||
}
|
||||
};
|
||||
launcher.getStateManager().addStateListener(listener);
|
||||
return listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows work apps edu if user had dismissed full edu flow
|
||||
*/
|
||||
public static void showWorkEduIfNeeded(Launcher launcher) {
|
||||
if (hasSeenLegacyEdu(launcher) || launcher.getSharedPrefs().getInt(KEY_WORK_EDU_STEP,
|
||||
WORK_EDU_NOT_STARTED) != WORK_EDU_PERSONAL_APPS) {
|
||||
return;
|
||||
}
|
||||
LayoutInflater layoutInflater = LayoutInflater.from(launcher);
|
||||
WorkEduView v = (WorkEduView) layoutInflater.inflate(
|
||||
R.layout.work_profile_edu, launcher.getDragLayer(), false);
|
||||
v.show();
|
||||
v.goToWorkTab(false);
|
||||
}
|
||||
|
||||
private static boolean hasSeenLegacyEdu(Launcher launcher) {
|
||||
return launcher.getSharedPrefs().getBoolean(KEY_LEGACY_WORK_EDU_SEEN, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateTransitionComplete(LauncherState finalState) {
|
||||
close(false);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package com.android.launcher3.widget;
|
||||
|
||||
import static com.android.launcher3.AppWidgetResizeFrame.getWidgetSizeOptions;
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
|
||||
|
||||
import android.appwidget.AppWidgetHostView;
|
||||
@@ -24,6 +23,7 @@ import android.os.Bundle;
|
||||
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.PendingAddItemInfo;
|
||||
import com.android.launcher3.widget.util.WidgetSizes;
|
||||
|
||||
/**
|
||||
* Meta data used for late binding of {@link LauncherAppWidgetProviderInfo}.
|
||||
@@ -61,6 +61,6 @@ public class PendingAddWidgetInfo extends PendingAddItemInfo {
|
||||
}
|
||||
|
||||
public Bundle getDefaultSizeOptions(Context context) {
|
||||
return getWidgetSizeOptions(context, componentName, spanX, spanY);
|
||||
return WidgetSizes.getWidgetSizeOptions(context, componentName, spanX, spanY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,12 +21,12 @@ import static com.android.launcher3.Utilities.ATLEAST_S;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.CancellationSignal;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Size;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
@@ -48,6 +48,7 @@ import com.android.launcher3.WidgetPreviewLoader;
|
||||
import com.android.launcher3.icons.FastBitmapDrawable;
|
||||
import com.android.launcher3.icons.RoundDrawableWrapper;
|
||||
import com.android.launcher3.model.WidgetItem;
|
||||
import com.android.launcher3.widget.util.WidgetSizes;
|
||||
|
||||
/**
|
||||
* Represents the individual cell of the widget inside the widget tray. The preview is drawn
|
||||
@@ -96,7 +97,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
|
||||
protected final BaseActivity mActivity;
|
||||
private final CheckLongPressHelper mLongPressHelper;
|
||||
private final float mEnforcedCornerRadius;
|
||||
private final int mPreviewPadding;
|
||||
private final int mShortcutPreviewPadding;
|
||||
|
||||
private RemoteViews mRemoteViewsPreview;
|
||||
private NavigableAppWidgetHostView mAppWidgetHostViewPreview;
|
||||
@@ -114,14 +115,14 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
|
||||
|
||||
mActivity = BaseActivity.fromContext(context);
|
||||
mLongPressHelper = new CheckLongPressHelper(this);
|
||||
|
||||
mLongPressHelper.setLongPressTimeoutFactor(1);
|
||||
|
||||
setContainerWidth();
|
||||
setWillNotDraw(false);
|
||||
setClipToPadding(false);
|
||||
setAccessibilityDelegate(mActivity.getAccessibilityDelegate());
|
||||
mEnforcedCornerRadius = RoundedCornerEnforcement.computeEnforcedRadius(context);
|
||||
mPreviewPadding =
|
||||
mShortcutPreviewPadding =
|
||||
2 * getResources().getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding);
|
||||
}
|
||||
|
||||
@@ -200,6 +201,8 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
|
||||
mWidgetPreviewLoader = loader;
|
||||
if (item.activityInfo != null) {
|
||||
setTag(new PendingAddShortcutInfo(item.activityInfo));
|
||||
mPreviewWidth += mShortcutPreviewPadding;
|
||||
mPreviewHeight += mShortcutPreviewPadding;
|
||||
} else {
|
||||
setTag(new PendingAddWidgetInfo(item.widgetInfo));
|
||||
}
|
||||
@@ -251,8 +254,6 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
|
||||
}
|
||||
appWidgetHostViewPreview.setPadding(padding.left, padding.top, padding.right,
|
||||
padding.bottom);
|
||||
mPreviewWidth += padding.left + padding.right;
|
||||
mPreviewHeight += padding.top + padding.bottom;
|
||||
appWidgetHostViewPreview.updateAppWidget(remoteViews);
|
||||
}
|
||||
|
||||
@@ -299,7 +300,7 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
|
||||
float scale = 1f;
|
||||
if (getWidth() > 0 && getHeight() > 0) {
|
||||
// Scale down the preview size if it's wider than the cell.
|
||||
float maxWidth = getWidth() - mPreviewPadding;
|
||||
float maxWidth = getWidth();
|
||||
float previewWidth = drawable.getIntrinsicWidth() * mPreviewScale;
|
||||
scale = Math.min(maxWidth / previewWidth, 1);
|
||||
}
|
||||
@@ -355,11 +356,9 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
|
||||
/** Sets the widget preview image size, in number of cells, and preview scale. */
|
||||
public void setPreviewSize(int spanX, int spanY, float previewScale) {
|
||||
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
|
||||
Point cellSize = deviceProfile.getCellSize();
|
||||
mPreviewWidth = cellSize.x * spanX + mPreviewPadding
|
||||
+ deviceProfile.cellLayoutBorderSpacingPx * (spanX - 1);
|
||||
mPreviewHeight = cellSize.y * spanY + mPreviewPadding
|
||||
+ deviceProfile.cellLayoutBorderSpacingPx * (spanY - 1);
|
||||
Size widgetSize = WidgetSizes.getWidgetSizePx(deviceProfile, spanX, spanY);
|
||||
mPreviewWidth = widgetSize.getWidth();
|
||||
mPreviewHeight = widgetSize.getHeight();
|
||||
mPreviewScale = previewScale;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.launcher3.widget.picker;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Size;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -33,6 +34,7 @@ import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.model.WidgetItem;
|
||||
import com.android.launcher3.widget.WidgetCell;
|
||||
import com.android.launcher3.widget.util.WidgetSizes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -44,7 +46,6 @@ public final class WidgetsRecommendationTableLayout extends TableLayout {
|
||||
private static final float MAX_DOWN_SCALE_RATIO = 0.5f;
|
||||
private final float mWidgetsRecommendationTableVerticalPadding;
|
||||
private final float mWidgetCellTextViewsHeight;
|
||||
private final float mWidgetPreviewPadding;
|
||||
|
||||
private float mRecommendationTableMaxHeight = Float.MAX_VALUE;
|
||||
@Nullable private OnLongClickListener mWidgetCellOnLongClickListener;
|
||||
@@ -61,8 +62,6 @@ public final class WidgetsRecommendationTableLayout extends TableLayout {
|
||||
mWidgetsRecommendationTableVerticalPadding = 2 * getResources()
|
||||
.getDimensionPixelSize(R.dimen.widget_cell_vertical_padding);
|
||||
mWidgetCellTextViewsHeight = 4 * getResources().getDimension(R.dimen.widget_cell_font_size);
|
||||
mWidgetPreviewPadding = 2 * getResources()
|
||||
.getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding);
|
||||
}
|
||||
|
||||
/** Sets a {@link android.view.View.OnLongClickListener} for all widget cells in this table. */
|
||||
@@ -149,8 +148,10 @@ public final class WidgetsRecommendationTableLayout extends TableLayout {
|
||||
List<WidgetItem> widgetItems = recommendedWidgetsInTable.get(i);
|
||||
float rowHeight = 0;
|
||||
for (int j = 0; j < widgetItems.size(); j++) {
|
||||
float previewHeight = widgetItems.get(j).spanY * deviceProfile.cellHeightPx
|
||||
* previewScale + mWidgetPreviewPadding;
|
||||
WidgetItem widgetItem = widgetItems.get(j);
|
||||
Size widgetSize = WidgetSizes.getWidgetSizePx(
|
||||
deviceProfile, widgetItem.spanX, widgetItem.spanY);
|
||||
float previewHeight = widgetSize.getHeight() * previewScale;
|
||||
rowHeight = Math.max(rowHeight, previewHeight + mWidgetCellTextViewsHeight);
|
||||
}
|
||||
totalHeight += rowHeight;
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.android.launcher3.widget.util;
|
||||
|
||||
import static android.appwidget.AppWidgetHostView.getDefaultPaddingForWidget;
|
||||
|
||||
import static com.android.launcher3.Utilities.ATLEAST_S;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.appwidget.AppWidgetHostView;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.util.Size;
|
||||
import android.util.SizeF;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/** A utility class for widget sizes related calculations. */
|
||||
public final class WidgetSizes {
|
||||
|
||||
/**
|
||||
* Returns the list of all possible sizes, in dp, for a widget of given spans on this device.
|
||||
*/
|
||||
public static ArrayList<SizeF> getWidgetSizes(Context context, int spanX, int spanY) {
|
||||
ArrayList<SizeF> sizes = new ArrayList<>(2);
|
||||
final float density = context.getResources().getDisplayMetrics().density;
|
||||
final Point cellSize = new Point();
|
||||
|
||||
for (DeviceProfile profile : LauncherAppState.getIDP(context).supportedProfiles) {
|
||||
Size widgetSizePx = getWidgetSizePx(profile, spanX, spanY, cellSize);
|
||||
sizes.add(new SizeF(widgetSizePx.getWidth() / density,
|
||||
widgetSizePx.getHeight() / density));
|
||||
}
|
||||
return sizes;
|
||||
}
|
||||
|
||||
/** Returns the size, in pixels, a widget of given spans & {@code profile}. */
|
||||
public static Size getWidgetSizePx(DeviceProfile profile, int spanX, int spanY) {
|
||||
return getWidgetSizePx(profile, spanX, spanY, /* recycledCellSize= */ null);
|
||||
}
|
||||
|
||||
private static Size getWidgetSizePx(DeviceProfile profile, int spanX, int spanY,
|
||||
@Nullable Point recycledCellSize) {
|
||||
final int hBorderSpacing = (spanX - 1) * profile.cellLayoutBorderSpacingPx;
|
||||
final int vBorderSpacing = (spanY - 1) * profile.cellLayoutBorderSpacingPx;
|
||||
if (recycledCellSize == null) {
|
||||
recycledCellSize = new Point();
|
||||
}
|
||||
profile.getCellSize(recycledCellSize);
|
||||
return new Size(((spanX * recycledCellSize.x) + hBorderSpacing),
|
||||
((spanY * recycledCellSize.y) + vBorderSpacing));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a given {@code widgetView} with size, {@code spanX}, {@code spanY}.
|
||||
*
|
||||
* <p>On Android S+, it also updates the given {@code widgetView} with a list of sizes derived
|
||||
* from {@code spanX}, {@code spanY} in all supported device profiles.
|
||||
*/
|
||||
@SuppressLint("NewApi") // Already added API check.
|
||||
public static void updateWidgetSizeRanges(AppWidgetHostView widgetView, Context context,
|
||||
int spanX, int spanY) {
|
||||
List<SizeF> sizes = getWidgetSizes(context, spanX, spanY);
|
||||
if (ATLEAST_S) {
|
||||
widgetView.updateAppWidgetSize(new Bundle(), sizes);
|
||||
} else {
|
||||
Rect bounds = getMinMaxSizes(sizes);
|
||||
widgetView.updateAppWidgetSize(new Bundle(), bounds.left, bounds.top, bounds.right,
|
||||
bounds.bottom);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bundle to be used as the default options for a widget with provided size.
|
||||
*/
|
||||
public static Bundle getWidgetSizeOptions(Context context, ComponentName provider, int spanX,
|
||||
int spanY) {
|
||||
ArrayList<SizeF> sizes = getWidgetSizes(context, spanX, spanY);
|
||||
Rect padding = getDefaultPaddingForWidget(context, provider, null);
|
||||
float density = context.getResources().getDisplayMetrics().density;
|
||||
float xPaddingDips = (padding.left + padding.right) / density;
|
||||
float yPaddingDips = (padding.top + padding.bottom) / density;
|
||||
|
||||
ArrayList<SizeF> paddedSizes = sizes.stream()
|
||||
.map(size -> new SizeF(
|
||||
Math.max(0.f, size.getWidth() - xPaddingDips),
|
||||
Math.max(0.f, size.getHeight() - yPaddingDips)))
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
|
||||
Rect rect = getMinMaxSizes(paddedSizes);
|
||||
Bundle options = new Bundle();
|
||||
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, rect.left);
|
||||
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, rect.top);
|
||||
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, rect.right);
|
||||
options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, rect.bottom);
|
||||
options.putParcelableArrayList(AppWidgetManager.OPTION_APPWIDGET_SIZES, paddedSizes);
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the min and max widths and heights given a list of sizes, in dp.
|
||||
*
|
||||
* @param sizes List of sizes to get the min/max from.
|
||||
* @return A rectangle with the left (resp. top) is used for the min width (resp. height) and
|
||||
* the right (resp. bottom) for the max. The returned rectangle is set with 0s if the list is
|
||||
* empty.
|
||||
*/
|
||||
private static Rect getMinMaxSizes(List<SizeF> sizes) {
|
||||
if (sizes.isEmpty()) {
|
||||
return new Rect();
|
||||
} else {
|
||||
SizeF first = sizes.get(0);
|
||||
Rect result = new Rect((int) first.getWidth(), (int) first.getHeight(),
|
||||
(int) first.getWidth(), (int) first.getHeight());
|
||||
for (int i = 1; i < sizes.size(); i++) {
|
||||
result.union((int) sizes.get(i).getWidth(), (int) sizes.get(i).getHeight());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,6 +126,7 @@ public class PersonalWorkSlidingTabStrip extends LinearLayout implements PageInd
|
||||
@Override
|
||||
public void setActiveMarker(int activePage) {
|
||||
updateTabTextColor(activePage);
|
||||
updateIndicatorPosition(activePage);
|
||||
if (mOnActivePageChangedListener != null && mLastActivePage != activePage) {
|
||||
mOnActivePageChangedListener.onActivePageChanged(activePage);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user