1 /* 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 */ 16 package com.android.launcher3.hybridhotseat; 17 18 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_EDU_ACCEPT; 19 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_EDU_DENY; 20 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOTSEAT_EDU_SEEN; 21 22 import android.content.Context; 23 import android.content.res.Configuration; 24 import android.graphics.Rect; 25 import android.util.AttributeSet; 26 import android.view.LayoutInflater; 27 import android.view.View; 28 import android.widget.Button; 29 import android.widget.LinearLayout; 30 import android.widget.TextView; 31 32 import com.android.launcher3.AbstractFloatingView; 33 import com.android.launcher3.CellLayout; 34 import com.android.launcher3.DeviceProfile; 35 import com.android.launcher3.Insettable; 36 import com.android.launcher3.InvariantDeviceProfile; 37 import com.android.launcher3.Launcher; 38 import com.android.launcher3.R; 39 import com.android.launcher3.celllayout.CellLayoutLayoutParams; 40 import com.android.launcher3.model.data.WorkspaceItemInfo; 41 import com.android.launcher3.uioverrides.PredictedAppIcon; 42 import com.android.launcher3.views.AbstractSlideInView; 43 44 import java.util.List; 45 46 /** 47 * User education dialog for hybrid hotseat. Allows user to migrate hotseat items to a new page in 48 * the workspace and shows predictions on the whole hotseat 49 */ 50 public class HotseatEduDialog extends AbstractSlideInView<Launcher> implements Insettable { 51 52 private static final int DEFAULT_CLOSE_DURATION = 200; 53 protected static final int FINAL_SCRIM_BG_COLOR = 0x88000000; 54 55 // we use this value to keep track of migration logs as we experiment with different migrations 56 private static final int MIGRATION_EXPERIMENT_IDENTIFIER = 1; 57 58 private final Rect mInsets = new Rect(); 59 private View mHotseatWrapper; 60 private CellLayout mSampleHotseat; 61 private Button mDismissBtn; 62 setHotseatEduController(HotseatEduController hotseatEduController)63 public void setHotseatEduController(HotseatEduController hotseatEduController) { 64 mHotseatEduController = hotseatEduController; 65 } 66 67 private HotseatEduController mHotseatEduController; 68 HotseatEduDialog(Context context, AttributeSet attr)69 public HotseatEduDialog(Context context, AttributeSet attr) { 70 this(context, attr, 0); 71 } 72 HotseatEduDialog(Context context, AttributeSet attrs, int defStyleAttr)73 public HotseatEduDialog(Context context, AttributeSet attrs, 74 int defStyleAttr) { 75 super(context, attrs, defStyleAttr); 76 mContent = this; 77 } 78 79 @Override onLayout(boolean changed, int l, int t, int r, int b)80 protected void onLayout(boolean changed, int l, int t, int r, int b) { 81 super.onLayout(changed, l, t, r, b); 82 setTranslationShift(TRANSLATION_SHIFT_CLOSED); 83 } 84 85 @Override onFinishInflate()86 protected void onFinishInflate() { 87 super.onFinishInflate(); 88 mHotseatWrapper = findViewById(R.id.hotseat_wrapper); 89 mSampleHotseat = findViewById(R.id.sample_prediction); 90 91 Context context = getContext(); 92 DeviceProfile grid = mActivityContext.getDeviceProfile(); 93 Rect padding = grid.getHotseatLayoutPadding(context); 94 95 mSampleHotseat.getLayoutParams().height = grid.cellHeightPx; 96 mSampleHotseat.setGridSize(grid.numShownHotseatIcons, 1); 97 mSampleHotseat.setPadding(padding.left, 0, padding.right, 0); 98 99 Button turnOnBtn = findViewById(R.id.turn_predictions_on); 100 turnOnBtn.setOnClickListener(this::onAccept); 101 102 mDismissBtn = findViewById(R.id.no_thanks); 103 mDismissBtn.setOnClickListener(this::onDismiss); 104 105 LinearLayout buttonContainer = findViewById(R.id.button_container); 106 int adjustedMarginEnd = grid.hotseatBarEndOffset - buttonContainer.getPaddingEnd(); 107 if (InvariantDeviceProfile.INSTANCE.get(context) 108 .getDeviceProfile(context).isTaskbarPresent && adjustedMarginEnd > 0) { 109 ((LinearLayout.LayoutParams) buttonContainer.getLayoutParams()).setMarginEnd( 110 adjustedMarginEnd); 111 } 112 } 113 onAccept(View v)114 private void onAccept(View v) { 115 mHotseatEduController.migrate(); 116 handleClose(true); 117 118 mHotseatEduController.moveHotseatItems(); 119 mHotseatEduController.finishOnboarding(); 120 mActivityContext.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_ACCEPT); 121 } 122 onDismiss(View v)123 private void onDismiss(View v) { 124 mHotseatEduController.showDimissTip(); 125 mHotseatEduController.finishOnboarding(); 126 mActivityContext.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_DENY); 127 handleClose(true); 128 } 129 130 @Override isOfType(int type)131 protected boolean isOfType(int type) { 132 return (type & TYPE_ON_BOARD_POPUP) != 0; 133 } 134 135 @Override setInsets(Rect insets)136 public void setInsets(Rect insets) { 137 int leftInset = insets.left - mInsets.left; 138 int rightInset = insets.right - mInsets.right; 139 int bottomInset = insets.bottom - mInsets.bottom; 140 mInsets.set(insets); 141 if (mActivityContext.getOrientation() == Configuration.ORIENTATION_PORTRAIT) { 142 setPadding(leftInset, getPaddingTop(), rightInset, 0); 143 mHotseatWrapper.setPadding(mHotseatWrapper.getPaddingLeft(), getPaddingTop(), 144 mHotseatWrapper.getPaddingRight(), bottomInset); 145 mHotseatWrapper.getLayoutParams().height = 146 mActivityContext.getDeviceProfile().hotseatBarSizePx + insets.bottom; 147 148 } else { 149 setPadding(0, getPaddingTop(), 0, 0); 150 mHotseatWrapper.setPadding(mHotseatWrapper.getPaddingLeft(), getPaddingTop(), 151 mHotseatWrapper.getPaddingRight(), 152 (int) getResources().getDimension(R.dimen.bottom_sheet_edu_padding)); 153 ((TextView) findViewById(R.id.hotseat_edu_heading)).setText( 154 R.string.hotseat_edu_title_migrate_landscape); 155 ((TextView) findViewById(R.id.hotseat_edu_content)).setText( 156 R.string.hotseat_edu_message_migrate_landscape); 157 } 158 } 159 animateOpen()160 private void animateOpen() { 161 if (mIsOpen || mOpenCloseAnimation.getAnimationPlayer().isRunning()) { 162 return; 163 } 164 mIsOpen = true; 165 setUpDefaultOpenAnimation().start(); 166 } 167 168 @Override handleClose(boolean animate)169 protected void handleClose(boolean animate) { 170 handleClose(true, DEFAULT_CLOSE_DURATION); 171 } 172 173 @Override onConfigurationChanged(Configuration newConfig)174 protected void onConfigurationChanged(Configuration newConfig) { 175 super.onConfigurationChanged(newConfig); 176 handleClose(false); 177 } 178 179 @Override getScrimColor(Context context)180 protected int getScrimColor(Context context) { 181 return FINAL_SCRIM_BG_COLOR; 182 } 183 populatePreview(List<WorkspaceItemInfo> predictions)184 private void populatePreview(List<WorkspaceItemInfo> predictions) { 185 for (int i = 0; i < mActivityContext.getDeviceProfile().numShownHotseatIcons; i++) { 186 WorkspaceItemInfo info = predictions.get(i); 187 PredictedAppIcon icon = PredictedAppIcon.createIcon(mSampleHotseat, info); 188 icon.setEnabled(false); 189 icon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); 190 icon.verifyHighRes(); 191 CellLayoutLayoutParams lp = new CellLayoutLayoutParams(i, 0, 1, 1); 192 mSampleHotseat.addViewToCellLayout(icon, i, info.getViewId(), lp, true); 193 } 194 } 195 196 /** 197 * Opens User education dialog with a list of suggested apps 198 */ show(List<WorkspaceItemInfo> predictions)199 public void show(List<WorkspaceItemInfo> predictions) { 200 if (getParent() != null 201 || predictions.size() < mActivityContext.getDeviceProfile().numShownHotseatIcons 202 || mHotseatEduController == null) { 203 return; 204 } 205 AbstractFloatingView.closeAllOpenViews(mActivityContext); 206 attachToContainer(); 207 animateOpen(); 208 populatePreview(predictions); 209 mActivityContext.getStatsLogManager().logger().log(LAUNCHER_HOTSEAT_EDU_SEEN); 210 } 211 212 /** 213 * Factory method for HotseatPredictionUserEdu dialog 214 */ getDialog(Launcher launcher)215 public static HotseatEduDialog getDialog(Launcher launcher) { 216 LayoutInflater layoutInflater = LayoutInflater.from(launcher); 217 return (HotseatEduDialog) layoutInflater.inflate( 218 R.layout.predicted_hotseat_edu, launcher.getDragLayer(), 219 false); 220 221 } 222 } 223