1 /* 2 * Copyright (C) 2017 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.views; 17 18 import android.animation.PropertyValuesHolder; 19 import android.content.Context; 20 import android.graphics.Rect; 21 import android.util.AttributeSet; 22 import android.view.LayoutInflater; 23 import android.view.TouchDelegate; 24 import android.view.View; 25 import android.view.accessibility.AccessibilityEvent; 26 27 import com.android.launcher3.Insettable; 28 import com.android.launcher3.Launcher; 29 import com.android.launcher3.R; 30 import com.android.launcher3.anim.Interpolators; 31 32 import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; 33 34 public class BottomUserEducationView extends AbstractSlideInView implements Insettable { 35 36 private static final String KEY_SHOWED_BOTTOM_USER_EDUCATION = "showed_bottom_user_education"; 37 38 private static final int DEFAULT_CLOSE_DURATION = 200; 39 40 private final Rect mInsets = new Rect(); 41 42 private View mCloseButton; 43 BottomUserEducationView(Context context, AttributeSet attr)44 public BottomUserEducationView(Context context, AttributeSet attr) { 45 this(context, attr, 0); 46 } 47 BottomUserEducationView(Context context, AttributeSet attrs, int defStyleAttr)48 public BottomUserEducationView(Context context, AttributeSet attrs, 49 int defStyleAttr) { 50 super(context, attrs, defStyleAttr); 51 mContent = this; 52 } 53 54 @Override onFinishInflate()55 protected void onFinishInflate() { 56 super.onFinishInflate(); 57 mCloseButton = findViewById(R.id.close_bottom_user_tip); 58 mCloseButton.setOnClickListener(view -> handleClose(true)); 59 } 60 61 @Override onLayout(boolean changed, int l, int t, int r, int b)62 protected void onLayout(boolean changed, int l, int t, int r, int b) { 63 super.onLayout(changed, l, t, r, b); 64 setTranslationShift(mTranslationShift); 65 expandTouchAreaOfCloseButton(); 66 } 67 68 @Override logActionCommand(int command)69 public void logActionCommand(int command) { 70 // Since this is on-boarding popup, it is not a user controlled action. 71 } 72 73 @Override isOfType(int type)74 protected boolean isOfType(int type) { 75 return (type & TYPE_ON_BOARD_POPUP) != 0; 76 } 77 78 @Override setInsets(Rect insets)79 public void setInsets(Rect insets) { 80 // Extend behind left, right, and bottom insets. 81 int leftInset = insets.left - mInsets.left; 82 int rightInset = insets.right - mInsets.right; 83 int bottomInset = insets.bottom - mInsets.bottom; 84 mInsets.set(insets); 85 setPadding(getPaddingLeft() + leftInset, getPaddingTop(), 86 getPaddingRight() + rightInset, getPaddingBottom() + bottomInset); 87 } 88 89 @Override handleClose(boolean animate)90 protected void handleClose(boolean animate) { 91 handleClose(animate, DEFAULT_CLOSE_DURATION); 92 if (animate) { 93 // We animate only when the user is visible, which is a proxy for an explicit 94 // close action. 95 mLauncher.getSharedPrefs().edit() 96 .putBoolean(KEY_SHOWED_BOTTOM_USER_EDUCATION, true).apply(); 97 sendCustomAccessibilityEvent( 98 BottomUserEducationView.this, 99 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED, 100 getContext().getString(R.string.bottom_work_tab_user_education_closed)); 101 } 102 } 103 open(boolean animate)104 private void open(boolean animate) { 105 if (mIsOpen || mOpenCloseAnimator.isRunning()) { 106 return; 107 } 108 mIsOpen = true; 109 if (animate) { 110 mOpenCloseAnimator.setValues( 111 PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED)); 112 mOpenCloseAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); 113 mOpenCloseAnimator.start(); 114 } else { 115 setTranslationShift(TRANSLATION_SHIFT_OPENED); 116 } 117 } 118 showIfNeeded(Launcher launcher)119 public static void showIfNeeded(Launcher launcher) { 120 if (launcher.getSharedPrefs().getBoolean(KEY_SHOWED_BOTTOM_USER_EDUCATION, false)) { 121 return; 122 } 123 124 LayoutInflater layoutInflater = LayoutInflater.from(launcher); 125 BottomUserEducationView bottomUserEducationView = 126 (BottomUserEducationView) layoutInflater.inflate( 127 R.layout.work_tab_bottom_user_education_view, launcher.getDragLayer(), 128 false); 129 launcher.getDragLayer().addView(bottomUserEducationView); 130 bottomUserEducationView.open(true); 131 } 132 expandTouchAreaOfCloseButton()133 private void expandTouchAreaOfCloseButton() { 134 Rect hitRect = new Rect(); 135 mCloseButton.getHitRect(hitRect); 136 hitRect.left -= mCloseButton.getWidth(); 137 hitRect.top -= mCloseButton.getHeight(); 138 hitRect.right += mCloseButton.getWidth(); 139 hitRect.bottom += mCloseButton.getHeight(); 140 View parent = (View) mCloseButton.getParent(); 141 parent.setTouchDelegate(new TouchDelegate(hitRect, mCloseButton)); 142 } 143 } 144