blob: bbc128f5ce0012988948c261747abd00ed59c518 [file] [log] [blame]
Samuel Fufaaed008d2019-12-19 10:57:40 -08001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.launcher3.hybridhotseat;
17
Samuel Fufab641ac22020-02-10 17:58:11 -080018import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
Samuel Fufaf667a132020-05-29 14:47:42 -070019import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType
20 .HYBRID_HOTSEAT_CANCELED;
Samuel Fufab641ac22020-02-10 17:58:11 -080021
Samuel Fufaaed008d2019-12-19 10:57:40 -080022import android.animation.PropertyValuesHolder;
23import android.content.Context;
24import android.content.res.Configuration;
25import android.graphics.Rect;
26import android.util.AttributeSet;
27import android.view.LayoutInflater;
28import android.view.View;
29import android.widget.Button;
Samuel Fufaa4211432020-02-25 18:47:54 -080030import android.widget.TextView;
Samuel Fufaaed008d2019-12-19 10:57:40 -080031
Samuel Fufa5b2da142020-05-28 16:55:26 -070032import com.android.launcher3.AbstractFloatingView;
Samuel Fufaaed008d2019-12-19 10:57:40 -080033import com.android.launcher3.CellLayout;
34import com.android.launcher3.DeviceProfile;
35import com.android.launcher3.Insettable;
36import com.android.launcher3.Launcher;
37import com.android.launcher3.R;
Samuel Fufa40846c62020-04-12 16:26:16 -070038import com.android.launcher3.Workspace;
Samuel Fufaaed008d2019-12-19 10:57:40 -080039import com.android.launcher3.anim.Interpolators;
Samuel Fufaa4211432020-02-25 18:47:54 -080040import com.android.launcher3.config.FeatureFlags;
Samuel Fufab641ac22020-02-10 17:58:11 -080041import com.android.launcher3.logging.UserEventDispatcher;
Sunny Goyale396abf2020-04-06 15:11:17 -070042import com.android.launcher3.model.data.WorkspaceItemInfo;
Samuel Fufaaed008d2019-12-19 10:57:40 -080043import com.android.launcher3.uioverrides.PredictedAppIcon;
44import com.android.launcher3.userevent.nano.LauncherLogProto;
45import com.android.launcher3.views.AbstractSlideInView;
46
47import java.util.List;
48
49/**
50 * User education dialog for hybrid hotseat. Allows user to migrate hotseat items to a new page in
51 * the workspace and shows predictions on the whole hotseat
52 */
53public class HotseatEduDialog extends AbstractSlideInView implements Insettable {
54
55 private static final int DEFAULT_CLOSE_DURATION = 200;
Samuel Fufaa4211432020-02-25 18:47:54 -080056 protected static final int FINAL_SCRIM_BG_COLOR = 0x88000000;
Samuel Fufaaed008d2019-12-19 10:57:40 -080057
Samuel Fufaa4211432020-02-25 18:47:54 -080058
Samuel Fufa82bbdac2020-03-09 18:24:47 -070059 // we use this value to keep track of migration logs as we experiment with different migrations
60 private static final int MIGRATION_EXPERIMENT_IDENTIFIER = 1;
Samuel Fufaaed008d2019-12-19 10:57:40 -080061
62 private final Rect mInsets = new Rect();
63 private View mHotseatWrapper;
64 private CellLayout mSampleHotseat;
Samuel Fufaa4211432020-02-25 18:47:54 -080065 private Button mDismissBtn;
66
Samuel Fufaaed008d2019-12-19 10:57:40 -080067 public void setHotseatEduController(HotseatEduController hotseatEduController) {
68 mHotseatEduController = hotseatEduController;
69 }
70
71 private HotseatEduController mHotseatEduController;
72
73 public HotseatEduDialog(Context context, AttributeSet attr) {
74 this(context, attr, 0);
75 }
76
77 public HotseatEduDialog(Context context, AttributeSet attrs,
78 int defStyleAttr) {
79 super(context, attrs, defStyleAttr);
80 mContent = this;
81 }
82
83
84 @Override
85 protected void onFinishInflate() {
86 super.onFinishInflate();
87 mHotseatWrapper = findViewById(R.id.hotseat_wrapper);
88 mSampleHotseat = findViewById(R.id.sample_prediction);
89
90 DeviceProfile grid = mLauncher.getDeviceProfile();
91 Rect padding = grid.getHotseatLayoutPadding();
92
93 mSampleHotseat.getLayoutParams().height = grid.cellHeightPx;
94 mSampleHotseat.setGridSize(grid.inv.numHotseatIcons, 1);
95 mSampleHotseat.setPadding(padding.left, 0, padding.right, 0);
96
97 Button turnOnBtn = findViewById(R.id.turn_predictions_on);
Samuel Fufaa4211432020-02-25 18:47:54 -080098 turnOnBtn.setOnClickListener(this::onAccept);
Samuel Fufaaed008d2019-12-19 10:57:40 -080099
Samuel Fufaa4211432020-02-25 18:47:54 -0800100 mDismissBtn = findViewById(R.id.no_thanks);
101 mDismissBtn.setOnClickListener(this::onDismiss);
Samuel Fufaaed008d2019-12-19 10:57:40 -0800102
Samuel Fufa82bbdac2020-03-09 18:24:47 -0700103 // update ui to reflect which migration method is going to be used
104 if (FeatureFlags.HOTSEAT_MIGRATE_TO_FOLDER.get()) {
105 ((TextView) findViewById(R.id.hotseat_edu_content)).setText(
106 R.string.hotseat_edu_message_migrate_alt);
107 }
Samuel Fufaaed008d2019-12-19 10:57:40 -0800108 }
109
Samuel Fufaa4211432020-02-25 18:47:54 -0800110 private void onAccept(View v) {
Samuel Fufa82bbdac2020-03-09 18:24:47 -0700111 mHotseatEduController.migrate();
Samuel Fufaaed008d2019-12-19 10:57:40 -0800112 handleClose(true);
Samuel Fufaaa2aff52020-03-24 18:34:12 -0700113
114 mHotseatEduController.moveHotseatItems();
Samuel Fufaaed008d2019-12-19 10:57:40 -0800115 mHotseatEduController.finishOnboarding();
Samuel Fufa82bbdac2020-03-09 18:24:47 -0700116 //TODO: pass actual page index here.
117 // Temporarily we're passing 1 for folder migration and 2 for page migration
118 logUserAction(true, FeatureFlags.HOTSEAT_MIGRATE_TO_FOLDER.get() ? 1 : 2);
Samuel Fufaaed008d2019-12-19 10:57:40 -0800119 }
120
Samuel Fufaa4211432020-02-25 18:47:54 -0800121 private void onDismiss(View v) {
Samuel Fufaaa2aff52020-03-24 18:34:12 -0700122 mHotseatEduController.showDimissTip();
Samuel Fufaaed008d2019-12-19 10:57:40 -0800123 mHotseatEduController.finishOnboarding();
Samuel Fufa82bbdac2020-03-09 18:24:47 -0700124 logUserAction(false, -1);
Samuel Fufaaed008d2019-12-19 10:57:40 -0800125 handleClose(true);
126 }
127
128 @Override
129 public void logActionCommand(int command) {
130 // Since this is on-boarding popup, it is not a user controlled action.
131 }
132
133 @Override
134 public int getLogContainerType() {
135 return LauncherLogProto.ContainerType.TIP;
136 }
137
138 @Override
139 protected boolean isOfType(int type) {
140 return (type & TYPE_ON_BOARD_POPUP) != 0;
141 }
142
143 @Override
144 public void setInsets(Rect insets) {
145 int leftInset = insets.left - mInsets.left;
146 int rightInset = insets.right - mInsets.right;
147 int bottomInset = insets.bottom - mInsets.bottom;
148 mInsets.set(insets);
Samuel Fufabe40b292020-05-18 12:50:29 -0700149 if (mLauncher.getOrientation() == Configuration.ORIENTATION_PORTRAIT) {
150 setPadding(leftInset, getPaddingTop(), rightInset, 0);
151 mHotseatWrapper.setPadding(mHotseatWrapper.getPaddingLeft(), getPaddingTop(),
152 mHotseatWrapper.getPaddingRight(), bottomInset);
153 mHotseatWrapper.getLayoutParams().height =
154 mLauncher.getDeviceProfile().hotseatBarSizePx + insets.bottom;
155
156 } else {
157 setPadding(0, getPaddingTop(), 0, 0);
158 mHotseatWrapper.setPadding(mHotseatWrapper.getPaddingLeft(), getPaddingTop(),
159 mHotseatWrapper.getPaddingRight(),
160 (int) getResources().getDimension(R.dimen.bottom_sheet_edu_padding));
161 ((TextView) findViewById(R.id.hotseat_edu_heading)).setText(
162 R.string.hotseat_edu_title_migrate_landscape);
163 ((TextView) findViewById(R.id.hotseat_edu_content)).setText(
164 R.string.hotseat_edu_message_migrate_landscape);
165 }
Samuel Fufaaed008d2019-12-19 10:57:40 -0800166 }
167
Samuel Fufa82bbdac2020-03-09 18:24:47 -0700168 private void logUserAction(boolean migrated, int pageIndex) {
Samuel Fufab641ac22020-02-10 17:58:11 -0800169 LauncherLogProto.Action action = new LauncherLogProto.Action();
170 LauncherLogProto.Target target = new LauncherLogProto.Target();
Samuel Fufa40846c62020-04-12 16:26:16 -0700171
172 int hotseatItemsCount = mLauncher.getHotseat().getShortcutsAndWidgets().getChildCount();
173 // -1 to exclude smart space
174 int workspaceItemCount = mLauncher.getWorkspace().getScreenWithId(
175 Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets().getChildCount() - 1;
176
Samuel Fufab641ac22020-02-10 17:58:11 -0800177 action.type = LauncherLogProto.Action.Type.TOUCH;
178 action.touch = LauncherLogProto.Action.Touch.TAP;
179 target.containerType = LauncherLogProto.ContainerType.TIP;
180 target.tipType = LauncherLogProto.TipType.HYBRID_HOTSEAT;
181 target.controlType = migrated ? LauncherLogProto.ControlType.HYBRID_HOTSEAT_ACCEPTED
182 : HYBRID_HOTSEAT_CANCELED;
Samuel Fufa82bbdac2020-03-09 18:24:47 -0700183 target.rank = MIGRATION_EXPERIMENT_IDENTIFIER;
Samuel Fufaa4211432020-02-25 18:47:54 -0800184 // encoding migration type on pageIndex
Samuel Fufa82bbdac2020-03-09 18:24:47 -0700185 target.pageIndex = pageIndex;
Samuel Fufa40846c62020-04-12 16:26:16 -0700186 target.cardinality = (workspaceItemCount * 1000) + hotseatItemsCount;
Samuel Fufab641ac22020-02-10 17:58:11 -0800187 LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
188 UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null);
189 }
Samuel Fufaaed008d2019-12-19 10:57:40 -0800190
Samuel Fufab641ac22020-02-10 17:58:11 -0800191 private void logOnBoardingSeen() {
192 LauncherLogProto.Action action = new LauncherLogProto.Action();
193 LauncherLogProto.Target target = new LauncherLogProto.Target();
194 action.type = LauncherLogProto.Action.Type.TIP;
195 target.containerType = LauncherLogProto.ContainerType.TIP;
196 target.tipType = LauncherLogProto.TipType.HYBRID_HOTSEAT;
197 LauncherLogProto.LauncherEvent event = newLauncherEvent(action, target);
198 UserEventDispatcher.newInstance(getContext()).dispatchUserEvent(event, null);
199 }
Samuel Fufaa4211432020-02-25 18:47:54 -0800200
Samuel Fufaaed008d2019-12-19 10:57:40 -0800201 private void animateOpen() {
202 if (mIsOpen || mOpenCloseAnimator.isRunning()) {
203 return;
204 }
205 mIsOpen = true;
206 mOpenCloseAnimator.setValues(
207 PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
208 mOpenCloseAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
209 mOpenCloseAnimator.start();
210 }
211
212 @Override
213 protected void handleClose(boolean animate) {
214 handleClose(true, DEFAULT_CLOSE_DURATION);
215 }
216
217 @Override
218 protected void onConfigurationChanged(Configuration newConfig) {
219 super.onConfigurationChanged(newConfig);
220 handleClose(false);
221 }
222
Samuel Fufaa4211432020-02-25 18:47:54 -0800223 @Override
224 protected int getScrimColor(Context context) {
225 return FINAL_SCRIM_BG_COLOR;
226 }
227
228 private void populatePreview(List<WorkspaceItemInfo> predictions) {
Samuel Fufaaed008d2019-12-19 10:57:40 -0800229 for (int i = 0; i < mLauncher.getDeviceProfile().inv.numHotseatIcons; i++) {
230 WorkspaceItemInfo info = predictions.get(i);
231 PredictedAppIcon icon = PredictedAppIcon.createIcon(mSampleHotseat, info);
232 icon.setEnabled(false);
Samuel Fufa6eaf9892020-04-01 11:40:40 -0700233 icon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
Samuel Fufaaed008d2019-12-19 10:57:40 -0800234 icon.verifyHighRes();
235 CellLayout.LayoutParams lp = new CellLayout.LayoutParams(i, 0, 1, 1);
236 mSampleHotseat.addViewToCellLayout(icon, i, info.getViewId(), lp, true);
237 }
238 }
239
Samuel Fufaa4211432020-02-25 18:47:54 -0800240 /**
241 * Opens User education dialog with a list of suggested apps
242 */
243 public void show(List<WorkspaceItemInfo> predictions) {
244 if (getParent() != null
245 || predictions.size() < mLauncher.getDeviceProfile().inv.numHotseatIcons
246 || mHotseatEduController == null) {
247 return;
248 }
Samuel Fufa5b2da142020-05-28 16:55:26 -0700249 AbstractFloatingView.closeAllOpenViews(mLauncher);
Samuel Fufaa4211432020-02-25 18:47:54 -0800250 attachToContainer();
251 logOnBoardingSeen();
252 animateOpen();
253 populatePreview(predictions);
254 }
255
Samuel Fufaaed008d2019-12-19 10:57:40 -0800256 /**
257 * Factory method for HotseatPredictionUserEdu dialog
258 */
259 public static HotseatEduDialog getDialog(Launcher launcher) {
260 LayoutInflater layoutInflater = LayoutInflater.from(launcher);
261 return (HotseatEduDialog) layoutInflater.inflate(
262 R.layout.predicted_hotseat_edu, launcher.getDragLayer(),
263 false);
264
265 }
266}