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

Show Arrow education tip on WidgetsBottomSheet. This tip is shown only
once either in widgets full sheet or bottom sheet.

Test: Tested manually
Bug: 185354491
Change-Id: I6d770ed0906a5cb0f5bcfe6ae0cd327b790cf164
This commit is contained in:
Alina Zaidi
2021-05-21 10:52:53 +01:00
parent 9f194ee290
commit 9d24de1353
5 changed files with 69 additions and 26 deletions

View File

@@ -21,7 +21,6 @@
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:background="@drawable/widgets_bottom_sheet_background"
android:elevation="@dimen/deep_shortcuts_elevation"
android:layout_gravity="bottom"
android:theme="?attr/widgetsTheme">

View File

@@ -196,7 +196,6 @@ public class ArrowTipView extends AbstractFloatingView {
parent.addView(this);
requestLayout();
post(() -> setY(yCoord - getHeight()));
post(() -> {
float halfWidth = getWidth() / 2f;
float xCoord;
@@ -208,7 +207,9 @@ public class ArrowTipView extends AbstractFloatingView {
xCoord = arrowXCoord - halfWidth;
}
setX(xCoord);
findViewById(R.id.arrow).setX(arrowXCoord - xCoord);
setY(yCoord - getHeight());
View arrowView = findViewById(R.id.arrow);
arrowView.setX(arrowXCoord - xCoord - arrowView.getWidth() / 2f);
requestLayout();
});

View File

@@ -26,6 +26,9 @@ import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.Launcher;
@@ -39,6 +42,7 @@ import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.AbstractSlideInView;
import com.android.launcher3.views.ArrowTipView;
/**
* Base class for various widgets popup
@@ -47,6 +51,9 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
implements OnClickListener, OnLongClickListener, DragSource,
PopupDataProvider.PopupDataChangeListener {
protected static final String KEY_WIDGETS_EDUCATION_TIP_SEEN =
"launcher.widgets_education_tip_seen";
/* Touch handling related member variables. */
private Toast mWidgetInstructionToast;
@@ -196,4 +203,28 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView<Launcher>
toast.show();
return toast;
}
/** Shows education tip on top center of {@code view} if view is laid out. */
@Nullable
protected ArrowTipView showEducationTipOnViewIfPossible(@Nullable View view) {
if (view == null || !ViewCompat.isLaidOut(view)) {
return null;
}
mActivityContext.getSharedPrefs().edit()
.putBoolean(KEY_WIDGETS_EDUCATION_TIP_SEEN, true).apply();
int[] coords = new int[2];
view.getLocationOnScreen(coords);
ArrowTipView arrowTipView = new ArrowTipView(mActivityContext);
return arrowTipView.showAtLocation(
getContext().getString(R.string.long_press_widget_to_add),
/* arrowXCoord= */coords[0] + view.getWidth() / 2,
/* yCoord= */coords[1]);
}
/** Returns {@code true} if tip has previously been shown on any of {@link BaseWidgetSheet}. */
protected boolean hasSeenEducationTip() {
return mActivityContext.getSharedPrefs().getBoolean(KEY_WIDGETS_EDUCATION_TIP_SEEN, false)
|| Utilities.IS_RUNNING_IN_TEST_HARNESS;
}
}

View File

@@ -68,12 +68,43 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable {
};
private static final int DEFAULT_CLOSE_DURATION = 200;
private static final long EDUCATION_TIP_DELAY_MS = 300;
private ItemInfo mOriginalItemInfo;
private Rect mInsets;
private final int mMaxTableHeight;
private int mMaxHorizontalSpan = 4;
private Configuration mCurrentConfiguration;
private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
new OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
if (hasSeenEducationTip()) {
removeOnLayoutChangeListener(this);
return;
}
// Widgets are loaded asynchronously, We are adding a delay because we only want
// to show the tip when the widget preview has finished loading and rendering in
// this view.
removeCallbacks(mShowEducationTipTask);
postDelayed(mShowEducationTipTask, EDUCATION_TIP_DELAY_MS);
}
};
private final Runnable mShowEducationTipTask = () -> {
if (hasSeenEducationTip()) {
removeOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
return;
}
View viewForTip = ((ViewGroup) ((TableLayout) findViewById(R.id.widgets_table))
.getChildAt(0)).getChildAt(0);
if (showEducationTipOnViewIfPossible(viewForTip) != null) {
removeOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
}
};
public WidgetsBottomSheet(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@@ -88,6 +119,9 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable {
// take over the entire view vertically.
mMaxTableHeight = deviceProfile.inv.numRows * 2 / 3 * deviceProfile.cellHeightPx;
mCurrentConfiguration = new Configuration(getResources().getConfiguration());
if (!hasSeenEducationTip()) {
addOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
}
}
@Override

View File

@@ -41,7 +41,6 @@ import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.DeviceProfile;
@@ -49,11 +48,9 @@ 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.widget.BaseWidgetSheet;
@@ -86,7 +83,6 @@ public class WidgetsFullSheet extends BaseWidgetSheet
// 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 WIDGETS_EDUCATION_TIP_SEEN = "launcher.widgets_education_tip_seen";
private final Rect mInsets = new Rect();
private final boolean mHasWorkProfile;
@@ -120,9 +116,8 @@ public class WidgetsFullSheet extends BaseWidgetSheet
return;
}
View viewForTip = getViewToShowEducationTip();
if (viewForTip != null && ViewCompat.isLaidOut(viewForTip)) {
if (showEducationTipOnViewIfPossible(viewForTip) != null) {
removeOnLayoutChangeListener(mLayoutChangeListenerToShowTips);
showEducationTipOnView(viewForTip);
}
};
private final int mTabsHeight;
@@ -618,18 +613,6 @@ public class WidgetsFullSheet extends BaseWidgetSheet
getWindowInsetsController().hide(WindowInsets.Type.ime());
}
private void showEducationTipOnView(View view) {
mActivityContext.getSharedPrefs().edit()
.putBoolean(WIDGETS_EDUCATION_TIP_SEEN, true).apply();
int[] coords = new int[2];
view.getLocationOnScreen(coords);
ArrowTipView arrowTipView = new ArrowTipView(mActivityContext);
arrowTipView.showAtLocation(
getContext().getString(R.string.long_press_widget_to_add),
/* arrowXCoord= */coords[0] + view.getWidth() / 2,
/* yCoord= */coords[1]);
}
@Nullable private View getViewToShowEducationTip() {
if (mSearchAndRecommendationViewHolder.mRecommendedWidgetsTable.getVisibility() == VISIBLE
&& mSearchAndRecommendationViewHolder.mRecommendedWidgetsTable.getChildCount() > 0
@@ -658,11 +641,6 @@ public class WidgetsFullSheet extends BaseWidgetSheet
return null;
}
private boolean hasSeenEducationTip() {
return mActivityContext.getSharedPrefs().getBoolean(WIDGETS_EDUCATION_TIP_SEEN, false)
|| Utilities.IS_RUNNING_IN_TEST_HARNESS;
}
/** A holder class for holding adapters & their corresponding recycler view. */
private final class AdapterHolder {
static final int PRIMARY = 0;