Add more education tips for widgets. (2/3)

Show education dialog on WidgetsFullSheet.
-Have a button in widget education dialog to intent into PixelTips apps.
-Make sure arrow tip view shows after dismissing education dialog on
WidgetsFullSheet if there is a widget to show it on.
-Update colors and layout for arrow tips.

Test: Tested manually
Bug: 185354491
Change-Id: I5cbdd02fc4f19a49a42dac4451b071e3d604747f
This commit is contained in:
Alina Zaidi 2021-05-27 14:55:21 +01:00
parent 755723403b
commit f2c79dea0d
30 changed files with 475 additions and 65 deletions

View File

@ -19,5 +19,5 @@
-->
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@android:color/white" />
<item android:color="?android:attr/textColorPrimaryInverse" />
</selector>

23
res/color/button_bg.xml Normal file
View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
**
** Copyright 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:color="?android:attr/colorAccent" />
</selector>

23
res/color/button_text.xml Normal file
View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
**
** Copyright 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:color="?android:attr/textColorPrimaryInverse" />
</selector>

View File

@ -16,7 +16,7 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/widgets_picker_surface" />
<solid android:color="@color/surface" />
<corners
android:topLeftRadius="?android:attr/dialogCornerRadius"
android:topRightRadius="?android:attr/dialogCornerRadius"

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="@color/widgets_picker_surface" />
<solid android:color="@color/surface" />
<corners
android:topLeftRadius="?android:attr/dialogCornerRadius"
android:topRightRadius="?android:attr/dialogCornerRadius" />

View File

@ -15,5 +15,5 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="@color/arrow_tip_view_bg" />
<corners android:radius="8dp" />
<corners android:radius="@dimen/dialogCornerRadius" />
</shape>

View File

@ -0,0 +1,23 @@
<?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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<solid android:color="@color/surface" />
<corners
android:topLeftRadius="@dimen/dialogCornerRadius"
android:topRightRadius="@dimen/dialogCornerRadius" />
</shape>

View File

@ -14,6 +14,6 @@
limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<solid android:color="@color/widgets_picker_surface" />
<solid android:color="@color/surface" />
<corners android:radius="24dp" />
</shape>

View File

@ -0,0 +1,32 @@
<?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.
-->
<inset
xmlns:android="http://schemas.android.com/apk/res/android">
<ripple
android:color="?android:attr/colorControlHighlight">
<item>
<shape android:shape="rectangle">
<corners
android:topLeftRadius="4dp"
android:topRightRadius="4dp"
android:bottomLeftRadius="12dp"
android:bottomRightRadius="12dp" />
<solid android:color="@color/button_bg"/>
</shape>
</item>
</ripple>
</inset>

View File

@ -0,0 +1,28 @@
<?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.
-->
<inset
xmlns:android="http://schemas.android.com/apk/res/android">
<ripple
android:color="?android:attr/colorControlHighlight">
<item>
<shape android:shape="rectangle">
<corners android:radius="12dp"/>
<solid android:color="@color/button_bg"/>
</shape>
</item>
</ripple>
</inset>

View File

@ -0,0 +1,35 @@
<?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.
-->
<inset
xmlns:android="http://schemas.android.com/apk/res/android">
<ripple
android:color="?android:attr/colorControlHighlight">
<item>
<shape android:shape="rectangle">
<corners
android:topLeftRadius="12dp"
android:topRightRadius="12dp"
android:bottomLeftRadius="4dp"
android:bottomRightRadius="4dp" />
<solid android:color="@color/surface"/>
<stroke
android:width="2dp"
android:color="@color/button_bg"/>
</shape>
</item>
</ripple>
</inset>

View File

@ -16,7 +16,7 @@
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/widgets_picker_surface" />
<solid android:color="@color/surface" />
<corners
android:topLeftRadius="@dimen/default_dialog_corner_radius"
android:topRightRadius="@dimen/default_dialog_corner_radius"

View File

@ -21,7 +21,7 @@
android:color="?android:attr/colorControlHighlight">
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="@color/widgets_picker_surface" />
<solid android:color="@color/surface" />
<corners
android:topLeftRadius="@dimen/widget_list_content_corner_radius"
android:topRightRadius="@dimen/widget_list_content_corner_radius"
@ -31,7 +31,7 @@
</item>
<item android:id="@android:id/background">
<shape android:shape="rectangle">
<solid android:color="@color/widgets_picker_surface" />
<solid android:color="@color/surface" />
<corners
android:topLeftRadius="@dimen/widget_list_content_corner_radius"
android:topRightRadius="@dimen/widget_list_content_corner_radius"

View File

@ -21,7 +21,7 @@
android:color="?android:attr/colorControlHighlight">
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="@color/widgets_picker_surface" />
<solid android:color="@color/surface" />
<corners
android:topLeftRadius="@dimen/widget_list_content_corner_radius"
android:topRightRadius="@dimen/widget_list_content_corner_radius"
@ -32,7 +32,7 @@
<item android:id="@android:id/background">
<shape android:shape="rectangle">
<solid android:color="@color/widgets_picker_surface" />
<solid android:color="@color/surface" />
<corners
android:topLeftRadius="@dimen/widget_list_content_corner_radius"
android:topRightRadius="@dimen/widget_list_content_corner_radius"

View File

@ -21,7 +21,7 @@
android:color="?android:attr/colorControlHighlight">
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="@color/widgets_picker_surface" />
<solid android:color="@color/surface" />
<corners
android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"
@ -31,7 +31,7 @@
</item>
<item android:id="@android:id/background">
<shape android:shape="rectangle">
<solid android:color="@color/widgets_picker_surface" />
<solid android:color="@color/surface" />
<corners
android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"

View File

@ -21,7 +21,7 @@
android:color="?android:attr/colorControlHighlight">
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="@color/widgets_picker_surface" />
<solid android:color="@color/surface" />
<corners
android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"
@ -32,7 +32,7 @@
<item android:id="@android:id/background">
<shape android:shape="rectangle">
<solid android:color="@color/widgets_picker_surface" />
<solid android:color="@color/surface" />
<corners
android:topLeftRadius="@dimen/widget_list_top_bottom_corner_radius"
android:topRightRadius="@dimen/widget_list_top_bottom_corner_radius"

View File

@ -19,6 +19,6 @@
-->
<shape android:shape="rectangle"
xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/widgets_picker_surface" />
<solid android:color="@color/surface" />
<corners android:radius="@dimen/widget_list_top_bottom_corner_radius"/>
</shape>

View File

@ -14,46 +14,22 @@
limitations under the License.
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="wrap_content">
<LinearLayout
<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="24dp"
android:paddingEnd="4dp"
android:background="@drawable/arrow_toast_rounded_background"
android:layout_gravity="center_horizontal"
android:gravity="center"
android:padding="16dp"
android:background="@drawable/arrow_toast_rounded_background"
android:elevation="2dp"
android:orientation="horizontal">
<TextView
android:id="@+id/text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:gravity="center"
android:layout_gravity="center_vertical"
android:textColor="@color/arrow_tip_view_content"
android:textSize="16sp" />
<ImageView
android:id="@+id/dismiss"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_vertical"
android:padding="10dp"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:alpha="0.7"
android:src="@drawable/ic_remove_no_shadow"
android:tint="@color/arrow_tip_view_content"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/accessibility_close" />
</LinearLayout>
android:textColor="@color/arrow_tip_view_content"
android:textSize="14sp"/>
<View
android:id="@+id/arrow"

View File

@ -0,0 +1,66 @@
<?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.
-->
<com.android.launcher3.views.WidgetsEduView
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">
<LinearLayout
android:id="@+id/edu_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_rounded_corner_bottom_sheet"
android:gravity="center_horizontal"
android:orientation="vertical"
android:paddingHorizontal="@dimen/bottom_sheet_edu_padding"
android:paddingTop="@dimen/bottom_sheet_edu_padding">
<TextView
style="@style/TextHeadline"
android:id="@+id/edu_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="@string/widget_education_header"
android:textColor="?android:attr/textColorPrimary"
android:textSize="24sp"
android:layout_marginBottom="16dp"/>
<TextView
android:id="@+id/edu_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="@string/widget_education_content"
android:textSize="14sp"
android:textColor="?android:attr/textColorSecondary"
android:layout_marginBottom="24dp"/>
<Button
android:id="@+id/edu_close_button"
style="@style/Button.Rounded.Colored"
android:layout_width="match_parent"
android:layout_height="56dp"
android:text="@string/widget_education_close_button"
android:textSize="16sp"
android:textColor="@color/button_text"
android:layout_marginBottom="8dp"/>
</LinearLayout>
</com.android.launcher3.views.WidgetsEduView>

19
res/values-v28/dimens.xml Normal file
View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 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.
-->
<resources>
<dimen name="dialogCornerRadius">?android:attr/dialogCornerRadius</dimen>
</resources>

View File

@ -144,7 +144,7 @@
<dimen name="widget_row_padding">8dp</dimen>
<dimen name="widget_row_divider">2dp</dimen>
<dimen name="widget_picker_education_tip_width">120dp</dimen>
<dimen name="widget_picker_education_tip_max_width">308dp</dimen>
<dimen name="widget_picker_education_tip_min_margin">4dp</dimen>
<dimen name="widget_picker_view_pager_top_padding">16dp</dimen>
@ -283,6 +283,7 @@
<!-- Theming related -->
<dimen name="default_dialog_corner_radius">8dp</dimen>
<dimen name="dialogCornerRadius">@dimen/default_dialog_corner_radius</dimen>
<!-- Onboarding bottomsheet related -->
<dimen name="bottom_sheet_edu_padding">24dp</dimen>

View File

@ -99,6 +99,15 @@
<!-- A widget category label for grouping widgets related to conversations. [CHAR_LIMIT=30] -->
<string name="widget_category_conversations">Conversations</string>
<!-- Title of a dialog. This dialog lets a user know how they can use widgets on their phone.
[CHAR_LIMIT=NONE] -->
<string name="widget_education_header">Useful info at your fingertips</string>
<!-- Dialog text. This dialog lets a user know how they can use widgets on their phone.
[CHAR_LIMIT=NONE] -->
<string name="widget_education_content">To get info without opening apps, you can add widgets to your Home screen</string>
<!-- Text on the button that closes the education dialog about widgets. [CHAR_LIMIT=50] -->
<string name="widget_education_close_button">Got it</string>
<!-- All Apps -->
<!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
<string name="all_apps_search_bar_hint">Search apps</string>

View File

@ -291,6 +291,21 @@
<item name="android:background">@drawable/add_item_dialog_button_background</item>
</style>
<style name="Button.TopRounded.Bordered" parent="@android:style/Widget.Material.Button">
<item name="android:background">@drawable/button_top_rounded_bordered_ripple</item>
<item name="android:stateListAnimator">@null</item>
</style>
<style name="Button.BottomRounded.Colored" parent="@android:style/Widget.Material.Button">
<item name="android:background">@drawable/button_bottom_rounded_colored_ripple</item>
<item name="android:stateListAnimator">@null</item>
</style>
<style name="Button.Rounded.Colored" parent="@android:style/Widget.Material.Button">
<item name="android:background">@drawable/button_rounded_colored_ripple</item>
<item name="android:stateListAnimator">@null</item>
</style>
<style name="AddItemActivityTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
<item name="widgetsTheme">@style/WidgetContainerTheme</item>
</style>

View File

@ -63,7 +63,8 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
TYPE_TASK_MENU,
TYPE_OPTIONS_POPUP,
TYPE_ICON_SURFACE,
TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP
TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP,
TYPE_WIDGETS_EDUCATION_DIALOG
})
@Retention(RetentionPolicy.SOURCE)
public @interface FloatingViewType {}
@ -85,17 +86,19 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
public static final int TYPE_ICON_SURFACE = 1 << 13;
public static final int TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP = 1 << 14;
public static final int TYPE_WIDGETS_EDUCATION_DIALOG = 1 << 15;
public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP
| TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
| TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE | TYPE_TASK_MENU
| TYPE_OPTIONS_POPUP | TYPE_SNACKBAR | TYPE_LISTENER | TYPE_ALL_APPS_EDU
| TYPE_ICON_SURFACE | TYPE_DRAG_DROP_POPUP | TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP;
| TYPE_ICON_SURFACE | TYPE_DRAG_DROP_POPUP | TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP
| TYPE_WIDGETS_EDUCATION_DIALOG;
// Type of popups which should be kept open during launcher rebind
public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
| TYPE_WIDGETS_BOTTOM_SHEET | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE
| TYPE_ALL_APPS_EDU | TYPE_ICON_SURFACE;
| TYPE_ALL_APPS_EDU | TYPE_ICON_SURFACE | TYPE_WIDGETS_EDUCATION_DIALOG;
// Usually we show the back button when a floating view is open. Instead, hide for these types.
public static final int TYPE_HIDE_BACK_BUTTON = TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE

View File

@ -105,10 +105,6 @@ public class ArrowTipView extends AbstractFloatingView {
private void init(Context context) {
inflate(context, R.layout.arrow_toast, this);
setOrientation(LinearLayout.VERTICAL);
View dismissButton = findViewById(R.id.dismiss);
dismissButton.setOnClickListener(view -> {
handleClose(true);
});
View arrowView = findViewById(R.id.arrow);
ViewGroup.LayoutParams arrowLp = arrowView.getLayoutParams();
@ -194,18 +190,18 @@ public class ArrowTipView extends AbstractFloatingView {
public ArrowTipView showAtLocation(String text, int arrowXCoord, int yCoord) {
ViewGroup parent = mActivity.getDragLayer();
@Px int parentViewWidth = parent.getWidth();
@Px int textViewWidth = getContext().getResources()
.getDimensionPixelSize(R.dimen.widget_picker_education_tip_width);
@Px int maxTextViewWidth = getContext().getResources()
.getDimensionPixelSize(R.dimen.widget_picker_education_tip_max_width);
@Px int minViewMargin = getContext().getResources()
.getDimensionPixelSize(R.dimen.widget_picker_education_tip_min_margin);
if (parentViewWidth < textViewWidth + 2 * minViewMargin) {
if (parentViewWidth < maxTextViewWidth + 2 * minViewMargin) {
Log.w(TAG, "Cannot display tip on a small screen of size: " + parentViewWidth);
return null;
}
TextView textView = findViewById(R.id.text);
textView.setText(text);
textView.setWidth(textViewWidth);
textView.setMaxWidth(maxTextViewWidth);
parent.addView(this);
requestLayout();

View File

@ -0,0 +1,118 @@
/*
* 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.views;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
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 com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
/**
* Education view about widgets.
*/
public class WidgetsEduView extends AbstractSlideInView<Launcher> implements Insettable {
private static final int DEFAULT_CLOSE_DURATION = 200;
protected static final int FINAL_SCRIM_BG_COLOR = 0x88000000;
private Rect mInsets = new Rect();
private View mEduView;
public WidgetsEduView(Context context, AttributeSet attr) {
this(context, attr, 0);
}
public WidgetsEduView(Context context, AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContent = this;
}
@Override
protected void handleClose(boolean animate) {
handleClose(true, DEFAULT_CLOSE_DURATION);
}
@Override
protected boolean isOfType(int type) {
return (type & TYPE_WIDGETS_EDUCATION_DIALOG) != 0;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mEduView = findViewById(R.id.edu_view);
findViewById(R.id.edu_close_button)
.setOnClickListener(v -> close(/* animate= */ 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);
mEduView.setPaddingRelative(mEduView.getPaddingStart(),
mEduView.getPaddingTop(), mEduView.getPaddingEnd(), bottomInset);
}
private void show() {
attachToContainer();
animateOpen();
}
@Override
protected int getScrimColor(Context context) {
return FINAL_SCRIM_BG_COLOR;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
setTranslationShift(mTranslationShift);
}
private void animateOpen() {
if (mIsOpen || mOpenCloseAnimator.isRunning()) {
return;
}
mIsOpen = true;
mOpenCloseAnimator.setValues(
PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
mOpenCloseAnimator.setInterpolator(FAST_OUT_SLOW_IN);
mOpenCloseAnimator.start();
}
/** Shows widget education dialog. */
public static WidgetsEduView showEducationDialog(Launcher launcher) {
LayoutInflater layoutInflater = LayoutInflater.from(launcher);
WidgetsEduView v = (WidgetsEduView) layoutInflater.inflate(
R.layout.widgets_edu, launcher.getDragLayer(), false);
v.show();
return v;
}
}

View File

@ -49,11 +49,14 @@ import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.views.ArrowTipView;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.TopRoundedCornerView;
import com.android.launcher3.views.WidgetsEduView;
import com.android.launcher3.widget.BaseWidgetSheet;
import com.android.launcher3.widget.LauncherAppWidgetHost.ProviderChangedListener;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
@ -79,12 +82,16 @@ public class WidgetsFullSheet extends BaseWidgetSheet
private static final long DEFAULT_OPEN_DURATION = 267;
private static final long FADE_IN_DURATION = 150;
private static final long EDUCATION_TIP_DELAY_MS = 200;
private static final long EDUCATION_DIALOG_DELAY_MS = 500;
private static final float VERTICAL_START_POSITION = 0.3f;
// The widget recommendation table can easily take over the entire screen on devices with small
// resolution or landscape on phone. This ratio defines the max percentage of content area that
// the table can display.
private static final float RECOMMENDATION_TABLE_HEIGHT_RATIO = 0.75f;
private static final String KEY_WIDGETS_EDUCATION_DIALOG_SEEN =
"launcher.widgets_education_dialog_seen";
private final Rect mInsets = new Rect();
private final boolean mHasWorkProfile;
private final SparseArray<AdapterHolder> mAdapters = new SparseArray();
@ -93,6 +100,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
entry -> mCurrentUser.equals(entry.mPkgItem.user);
private final Predicate<WidgetsListBaseEntry> mWorkWidgetsFilter =
mPrimaryWidgetsFilter.negate();
@Nullable private ArrowTipView mLatestEducationalTip;
private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
new OnLayoutChangeListener() {
@Override
@ -116,11 +124,12 @@ public class WidgetsFullSheet extends BaseWidgetSheet
removeOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
return;
}
View viewForTip = getViewToShowEducationTip();
if (showEducationTipOnViewIfPossible(viewForTip) != null) {
mLatestEducationalTip = showEducationTipOnViewIfPossible(getViewToShowEducationTip());
if (mLatestEducationalTip != null) {
removeOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
}
};
private final int mTabsHeight;
private final int mViewPagerTopPadding;
private final int mWidgetCellHorizontalPadding;
@ -211,9 +220,7 @@ public class WidgetsFullSheet extends BaseWidgetSheet
mSearchAndRecommendationViewHolder.mSearchBar.initialize(
mActivityContext.getPopupDataProvider(), /* searchModeListener= */ this);
if (!hasSeenEducationTip()) {
addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
}
setUpEducationViewsIfNeeded();
}
@Override
@ -598,6 +605,10 @@ public class WidgetsFullSheet extends BaseWidgetSheet
@Override
protected void onCloseComplete() {
super.onCloseComplete();
removeCallbacks(mShowEducationTipTask);
if (mLatestEducationalTip != null) {
mLatestEducationalTip.close(false);
}
AccessibilityManagerCompat.sendStateEventToTest(getContext(), NORMAL_STATE_ORDINAL);
}
@ -670,6 +681,38 @@ public class WidgetsFullSheet extends BaseWidgetSheet
return null;
}
/** Shows education dialog for widgets. */
private WidgetsEduView showEducationDialog() {
mActivityContext.getSharedPrefs().edit()
.putBoolean(KEY_WIDGETS_EDUCATION_DIALOG_SEEN, true).apply();
return WidgetsEduView.showEducationDialog(mActivityContext);
}
/** Returns {@code true} if education dialog has previously been shown. */
protected boolean hasSeenEducationDialog() {
return mActivityContext.getSharedPrefs()
.getBoolean(KEY_WIDGETS_EDUCATION_DIALOG_SEEN, false)
|| Utilities.IS_RUNNING_IN_TEST_HARNESS;
}
private void setUpEducationViewsIfNeeded() {
if (!hasSeenEducationDialog()) {
postDelayed(() -> {
WidgetsEduView eduDialog = showEducationDialog();
eduDialog.addOnCloseListener(() -> {
if (!hasSeenEducationTip()) {
addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
// Call #requestLayout() to trigger layout change listener in order to show
// arrow tip immediately if there is a widget to show it on.
requestLayout();
}
});
}, EDUCATION_DIALOG_DELAY_MS);
} else if (!hasSeenEducationTip()) {
addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
}
}
/** A holder class for holding adapters & their corresponding recycler view. */
private final class AdapterHolder {
static final int PRIMARY = 0;