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.allapps; 17 18 import android.content.Context; 19 import android.content.SharedPreferences; 20 import android.graphics.Rect; 21 import android.os.AsyncTask; 22 import android.os.Process; 23 import android.os.UserHandle; 24 import android.os.UserManager; 25 import android.util.AttributeSet; 26 import android.view.MotionEvent; 27 import android.view.ViewConfiguration; 28 import android.widget.Switch; 29 30 import com.android.launcher3.Insettable; 31 import com.android.launcher3.R; 32 import com.android.launcher3.Utilities; 33 import com.android.launcher3.pm.UserCache; 34 import com.android.launcher3.views.ArrowTipView; 35 36 import java.lang.ref.WeakReference; 37 38 /** 39 * Work profile toggle switch shown at the bottom of AllApps work tab 40 */ 41 public class WorkModeSwitch extends Switch implements Insettable { 42 43 private static final int WORK_TIP_THRESHOLD = 2; 44 public static final String KEY_WORK_TIP_COUNTER = "worked_tip_counter"; 45 46 private Rect mInsets = new Rect(); 47 48 private final float[] mTouch = new float[2]; 49 private int mTouchSlop; 50 WorkModeSwitch(Context context)51 public WorkModeSwitch(Context context) { 52 super(context); 53 init(); 54 } 55 WorkModeSwitch(Context context, AttributeSet attrs)56 public WorkModeSwitch(Context context, AttributeSet attrs) { 57 super(context, attrs); 58 init(); 59 } 60 WorkModeSwitch(Context context, AttributeSet attrs, int defStyleAttr)61 public WorkModeSwitch(Context context, AttributeSet attrs, int defStyleAttr) { 62 super(context, attrs, defStyleAttr); 63 init(); 64 } 65 init()66 private void init() { 67 ViewConfiguration viewConfiguration = ViewConfiguration.get(getContext()); 68 mTouchSlop = viewConfiguration.getScaledTouchSlop(); 69 } 70 71 @Override setChecked(boolean checked)72 public void setChecked(boolean checked) { } 73 74 @Override toggle()75 public void toggle() { 76 // don't show tip if user uses toggle 77 Utilities.getPrefs(getContext()).edit().putInt(KEY_WORK_TIP_COUNTER, -1).apply(); 78 trySetQuietModeEnabledToAllProfilesAsync(isChecked()); 79 } 80 81 /** 82 * Sets the enabled or disabled state of the button 83 * @param isChecked 84 */ update(boolean isChecked)85 public void update(boolean isChecked) { 86 super.setChecked(isChecked); 87 setCompoundDrawablesRelativeWithIntrinsicBounds( 88 isChecked ? R.drawable.ic_corp : R.drawable.ic_corp_off, 0, 0, 0); 89 setEnabled(true); 90 } 91 92 @Override onTouchEvent(MotionEvent ev)93 public boolean onTouchEvent(MotionEvent ev) { 94 if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { 95 mTouch[0] = ev.getX(); 96 mTouch[1] = ev.getY(); 97 } else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) { 98 if (Math.abs(mTouch[0] - ev.getX()) > mTouchSlop 99 || Math.abs(mTouch[1] - ev.getY()) > mTouchSlop) { 100 int action = ev.getAction(); 101 ev.setAction(MotionEvent.ACTION_CANCEL); 102 super.onTouchEvent(ev); 103 ev.setAction(action); 104 return false; 105 } 106 } 107 return super.onTouchEvent(ev); 108 } 109 trySetQuietModeEnabledToAllProfilesAsync(boolean enabled)110 private void trySetQuietModeEnabledToAllProfilesAsync(boolean enabled) { 111 new SetQuietModeEnabledAsyncTask(enabled, new WeakReference<>(this)).execute(); 112 } 113 114 @Override setInsets(Rect insets)115 public void setInsets(Rect insets) { 116 int bottomInset = insets.bottom - mInsets.bottom; 117 mInsets.set(insets); 118 setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), 119 getPaddingBottom() + bottomInset); 120 } 121 122 /** 123 * Animates in/out work profile toggle panel based on the tab user is on 124 */ setWorkTabVisible(boolean workTabVisible)125 public void setWorkTabVisible(boolean workTabVisible) { 126 clearAnimation(); 127 if (workTabVisible) { 128 setVisibility(VISIBLE); 129 setAlpha(0); 130 animate().alpha(1).start(); 131 showTipIfNeeded(); 132 } else { 133 animate().alpha(0).withEndAction(() -> this.setVisibility(GONE)).start(); 134 } 135 } 136 137 private static final class SetQuietModeEnabledAsyncTask 138 extends AsyncTask<Void, Void, Boolean> { 139 140 private final boolean enabled; 141 private final WeakReference<WorkModeSwitch> switchWeakReference; 142 SetQuietModeEnabledAsyncTask(boolean enabled, WeakReference<WorkModeSwitch> switchWeakReference)143 SetQuietModeEnabledAsyncTask(boolean enabled, 144 WeakReference<WorkModeSwitch> switchWeakReference) { 145 this.enabled = enabled; 146 this.switchWeakReference = switchWeakReference; 147 } 148 149 @Override onPreExecute()150 protected void onPreExecute() { 151 super.onPreExecute(); 152 WorkModeSwitch workModeSwitch = switchWeakReference.get(); 153 if (workModeSwitch != null) { 154 workModeSwitch.setEnabled(false); 155 } 156 } 157 158 @Override doInBackground(Void... voids)159 protected Boolean doInBackground(Void... voids) { 160 WorkModeSwitch workModeSwitch = switchWeakReference.get(); 161 if (workModeSwitch == null || !Utilities.ATLEAST_P) { 162 return false; 163 } 164 165 Context context = workModeSwitch.getContext(); 166 UserManager userManager = context.getSystemService(UserManager.class); 167 boolean showConfirm = false; 168 for (UserHandle userProfile : UserCache.INSTANCE.get(context).getUserProfiles()) { 169 if (Process.myUserHandle().equals(userProfile)) { 170 continue; 171 } 172 showConfirm |= !userManager.requestQuietModeEnabled(enabled, userProfile); 173 } 174 return showConfirm; 175 } 176 177 @Override onPostExecute(Boolean showConfirm)178 protected void onPostExecute(Boolean showConfirm) { 179 if (showConfirm) { 180 WorkModeSwitch workModeSwitch = switchWeakReference.get(); 181 if (workModeSwitch != null) { 182 workModeSwitch.setEnabled(true); 183 } 184 } 185 } 186 } 187 188 /** 189 * Shows a work tip on the Nth work tab open 190 */ showTipIfNeeded()191 public void showTipIfNeeded() { 192 Context context = getContext(); 193 SharedPreferences prefs = Utilities.getPrefs(context); 194 int tipCounter = prefs.getInt(KEY_WORK_TIP_COUNTER, WORK_TIP_THRESHOLD); 195 if (tipCounter < 0) return; 196 if (tipCounter == 0) { 197 new ArrowTipView(context) 198 .show(context.getString(R.string.work_switch_tip), getTop()); 199 } 200 prefs.edit().putInt(KEY_WORK_TIP_COUNTER, tipCounter - 1).apply(); 201 } 202 } 203