Merge "[AllApps][Work] Introduce work toggle Fab" into sc-dev
This commit is contained in:
commit
2f346b8666
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_enabled="false">
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="@dimen/work_fab_radius" />
|
||||
<solid android:color="?android:attr/colorControlHighlight" />
|
||||
<padding android:left="@dimen/work_fab_radius" android:right="@dimen/work_fab_radius" />
|
||||
</shape>
|
||||
</item>
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="@dimen/work_fab_radius" />
|
||||
<solid android:color="?android:attr/colorAccent" />
|
||||
<padding android:left="@dimen/work_fab_radius" android:right="@dimen/work_fab_radius" />
|
||||
</shape>
|
||||
</item>
|
||||
</selector>
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.launcher3.allapps.WorkModeSwitch
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/work_mode_toggle"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_height="@dimen/work_fab_height"
|
||||
android:layout_width="wrap_content"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:drawableTint="@android:color/white"
|
||||
android:textColor="@android:color/white"
|
||||
android:background="@drawable/work_apps_toggle_background"
|
||||
android:drawablePadding="16dp"
|
||||
android:drawableStart="@drawable/ic_corp_off"
|
||||
android:elevation="10dp"
|
||||
android:layout_marginBottom="@dimen/work_fab_margin"
|
||||
android:layout_marginEnd="@dimen/work_fab_margin"
|
||||
android:text="@string/work_apps_pause_btn_text" />
|
|
@ -1,5 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2017 The Android Open Source Project
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
@ -13,8 +12,7 @@
|
|||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.launcher3.allapps.WorkModeSwitch
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<com.android.launcher3.allapps.WorkModeSwitch xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/PrimaryHeadline"
|
||||
|
@ -35,5 +33,4 @@
|
|||
android:paddingBottom="@dimen/work_profile_footer_padding"
|
||||
android:paddingLeft="@dimen/work_profile_footer_padding"
|
||||
android:paddingRight="@dimen/work_profile_footer_padding"
|
||||
android:paddingTop="@dimen/work_profile_footer_padding"
|
||||
/>
|
||||
android:paddingTop="@dimen/work_profile_footer_padding" />
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2020 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<com.android.launcher3.views.WorkEduView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:gravity="bottom"
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="32dp"
|
||||
android:background="@drawable/bottom_sheet_top_border"
|
||||
android:backgroundTint="?attr/eduHalfSheetBGColor" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/view_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/eduHalfSheetBGColor"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@dimen/bottom_sheet_edu_padding"
|
||||
android:paddingRight="@dimen/bottom_sheet_edu_padding">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/content_text"
|
||||
style="@style/TextHeadline"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="48dp"
|
||||
android:layout_marginBottom="48dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/work_profile_edu_personal_apps"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/proceed"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="end"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:gravity="center"
|
||||
android:text="@string/work_profile_edu_next"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@android:color/white" />
|
||||
</LinearLayout>
|
||||
</com.android.launcher3.views.WorkEduView>
|
|
@ -116,6 +116,10 @@
|
|||
|
||||
<dimen name="all_apps_divider_margin_vertical">8dp</dimen>
|
||||
|
||||
<!-- Floating action button inside work tab to toggle work profile -->
|
||||
<dimen name="work_fab_height">48dp</dimen>
|
||||
<dimen name="work_fab_radius">24dp</dimen>
|
||||
<dimen name="work_fab_margin">18dp</dimen>
|
||||
<dimen name="work_profile_footer_padding">20dp</dimen>
|
||||
<dimen name="work_profile_footer_text_size">16sp</dimen>
|
||||
|
||||
|
|
|
@ -388,37 +388,30 @@
|
|||
|
||||
<!-- This string is in the work profile tab when a user has All Apps open on their phone. This is a label for a toggle to turn the work profile on and off. "Work profile" means a separate profile on a user's phone that's specifically for their work apps and managed by their company. "Work" is used as an adjective.-->
|
||||
<string name="work_profile_toggle_label">Work profile</string>
|
||||
<!--- User onboarding title for personal apps -->
|
||||
<string name="work_profile_edu_personal_apps">Personal data is separate & hidden from work apps</string>
|
||||
<!--- User onboarding title for work profile apps -->
|
||||
<string name="work_profile_edu_work_apps">Work apps & data are visible to your IT admin</string>
|
||||
<!-- Action label to proceed to the next work profile edu section-->
|
||||
<string name="work_profile_edu_next">Next</string>
|
||||
<string name="work_profile_edu_work_apps">Work apps are badged andare visible to your IT admin</string>
|
||||
<!-- Action label to finish work profile edu-->
|
||||
<string name="work_profile_edu_accept">Got it</string>
|
||||
|
||||
<!--- heading shown when user opens work apps tab while work apps are paused -->
|
||||
<string name="work_apps_paused_title">Work profile is paused</string>
|
||||
<string name="work_apps_paused_title">Work apps are off</string>
|
||||
<!--- body shown when user opens work apps tab while work apps are paused -->
|
||||
<string name="work_apps_paused_body">Work apps can’t send you notifications, use your battery, or access your location</string>
|
||||
<string name="work_apps_paused_body">Your work apps can’t send you notifications, use your battery, or access your location</string>
|
||||
<!-- content description for paused work apps list -->
|
||||
<string name="work_apps_paused_content_description">Work profile is paused. Work apps can’t send you notifications, use your battery, or access your location</string>
|
||||
<string name="work_apps_paused_content_description">Work apps are off. Your work apps can’t send you notifications, use your battery, or access your location</string>
|
||||
<!-- string shown in educational banner about work profile -->
|
||||
<string name="work_apps_paused_edu_banner">Work apps are badged and visible to your IT admin</string>
|
||||
<!-- button string shown to dismiss work tab education -->
|
||||
<string name="work_apps_paused_edu_accept">Got it</string>
|
||||
|
||||
<!-- button string shown pause work profile -->
|
||||
<string name="work_apps_pause_btn_text">Pause work apps</string>
|
||||
<string name="work_apps_pause_btn_text">Turn off work apps</string>
|
||||
<!-- button string shown enable work profile -->
|
||||
<string name="work_apps_enable_btn_text">Turn on</string>
|
||||
<string name="work_apps_enable_btn_text">Turn on work apps</string>
|
||||
|
||||
<!-- A hint shown in launcher settings develop options filter box -->
|
||||
<string name="developer_options_filter_hint">Filter</string>
|
||||
|
||||
<!-- A tip shown pointing at work toggle -->
|
||||
<string name="work_switch_tip">Pause work apps and notifications</string>
|
||||
|
||||
<!-- Failed action error message: e.g. Failed: Pause -->
|
||||
<string name="remote_action_failed">Failed: <xliff:g id="what" example="Pause">%1$s</xliff:g></string>
|
||||
</resources>
|
||||
|
|
|
@ -228,7 +228,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
|||
}
|
||||
|
||||
private void resetWorkProfile() {
|
||||
mWorkModeSwitch.update(!mAllAppsStore.hasModelFlag(FLAG_QUIET_MODE_ENABLED));
|
||||
mWorkModeSwitch.updateCurrentState(!mAllAppsStore.hasModelFlag(FLAG_QUIET_MODE_ENABLED));
|
||||
mAH[AdapterHolder.WORK].setupOverlay();
|
||||
mAH[AdapterHolder.WORK].applyPadding();
|
||||
}
|
||||
|
@ -482,7 +482,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
|
|||
private void setupWorkToggle() {
|
||||
if (Utilities.ATLEAST_P) {
|
||||
mWorkModeSwitch = (WorkModeSwitch) mLauncher.getLayoutInflater().inflate(
|
||||
R.layout.work_mode_switch, this, false);
|
||||
R.layout.work_mode_fab, this, false);
|
||||
this.addView(mWorkModeSwitch);
|
||||
mWorkModeSwitch.setInsets(mInsets);
|
||||
mWorkModeSwitch.post(this::resetWorkProfile);
|
||||
|
|
|
@ -25,7 +25,6 @@ import android.view.MotionEvent;
|
|||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.statemanager.StateManager.StateListener;
|
||||
import com.android.launcher3.views.WorkEduView;
|
||||
|
||||
/**
|
||||
* AllAppsContainerView with launcher specific callbacks
|
||||
|
@ -88,13 +87,6 @@ public class LauncherAllAppsContainerView extends AllAppsContainerView {
|
|||
@Override
|
||||
public void onActivePageChanged(int currentActivePage) {
|
||||
super.onActivePageChanged(currentActivePage);
|
||||
if (mUsingTabs) {
|
||||
if (currentActivePage == AdapterHolder.WORK) {
|
||||
WorkEduView.showWorkEduIfNeeded(mLauncher);
|
||||
} else {
|
||||
mWorkTabListener = WorkEduView.showEduFlowIfNeeded(mLauncher, mWorkTabListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,108 +15,61 @@
|
|||
*/
|
||||
package com.android.launcher3.allapps;
|
||||
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Rect;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.widget.Switch;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.pm.UserCache;
|
||||
import com.android.launcher3.views.ArrowTipView;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* Work profile toggle switch shown at the bottom of AllApps work tab
|
||||
*/
|
||||
public class WorkModeSwitch extends Switch implements Insettable {
|
||||
|
||||
private static final int WORK_TIP_THRESHOLD = 2;
|
||||
public static final String KEY_WORK_TIP_COUNTER = "worked_tip_counter";
|
||||
public class WorkModeSwitch extends Button implements Insettable, View.OnClickListener {
|
||||
|
||||
private Rect mInsets = new Rect();
|
||||
|
||||
private final float[] mTouch = new float[2];
|
||||
private int mTouchSlop;
|
||||
private boolean mWorkEnabled;
|
||||
|
||||
public WorkModeSwitch(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
this(context, null, 0);
|
||||
}
|
||||
|
||||
public WorkModeSwitch(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public WorkModeSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
ViewConfiguration viewConfiguration = ViewConfiguration.get(getContext());
|
||||
mTouchSlop = viewConfiguration.getScaledTouchSlop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChecked(boolean checked) { }
|
||||
|
||||
@Override
|
||||
public void toggle() {
|
||||
// don't show tip if user uses toggle
|
||||
Utilities.getPrefs(getContext()).edit().putInt(KEY_WORK_TIP_COUNTER, -1).apply();
|
||||
trySetQuietModeEnabledToAllProfilesAsync(isChecked());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the enabled or disabled state of the button
|
||||
* @param isChecked
|
||||
*/
|
||||
public void update(boolean isChecked) {
|
||||
super.setChecked(isChecked);
|
||||
setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||
isChecked ? R.drawable.ic_corp : R.drawable.ic_corp_off, 0, 0, 0);
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
||||
mTouch[0] = ev.getX();
|
||||
mTouch[1] = ev.getY();
|
||||
} else if (ev.getActionMasked() == MotionEvent.ACTION_MOVE) {
|
||||
if (Math.abs(mTouch[0] - ev.getX()) > mTouchSlop
|
||||
|| Math.abs(mTouch[1] - ev.getY()) > mTouchSlop) {
|
||||
int action = ev.getAction();
|
||||
ev.setAction(MotionEvent.ACTION_CANCEL);
|
||||
super.onTouchEvent(ev);
|
||||
ev.setAction(action);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return super.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
private void trySetQuietModeEnabledToAllProfilesAsync(boolean enabled) {
|
||||
new SetQuietModeEnabledAsyncTask(enabled, new WeakReference<>(this)).execute();
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInsets(Rect insets) {
|
||||
int bottomInset = insets.bottom - mInsets.bottom;
|
||||
mInsets.set(insets);
|
||||
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
|
||||
getPaddingBottom() + bottomInset);
|
||||
ViewGroup.MarginLayoutParams marginLayoutParams =
|
||||
(ViewGroup.MarginLayoutParams) getLayoutParams();
|
||||
if (marginLayoutParams != null) {
|
||||
marginLayoutParams.bottomMargin = bottomInset + marginLayoutParams.bottomMargin;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,78 +78,44 @@ public class WorkModeSwitch extends Switch implements Insettable {
|
|||
public void setWorkTabVisible(boolean workTabVisible) {
|
||||
clearAnimation();
|
||||
if (workTabVisible) {
|
||||
setEnabled(true);
|
||||
setVisibility(VISIBLE);
|
||||
setAlpha(0);
|
||||
animate().alpha(1).start();
|
||||
showTipIfNeeded();
|
||||
} else {
|
||||
animate().alpha(0).withEndAction(() -> this.setVisibility(GONE)).start();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class SetQuietModeEnabledAsyncTask
|
||||
extends AsyncTask<Void, Void, Boolean> {
|
||||
|
||||
private final boolean enabled;
|
||||
private final WeakReference<WorkModeSwitch> switchWeakReference;
|
||||
|
||||
SetQuietModeEnabledAsyncTask(boolean enabled,
|
||||
WeakReference<WorkModeSwitch> switchWeakReference) {
|
||||
this.enabled = enabled;
|
||||
this.switchWeakReference = switchWeakReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
WorkModeSwitch workModeSwitch = switchWeakReference.get();
|
||||
if (workModeSwitch != null) {
|
||||
workModeSwitch.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... voids) {
|
||||
WorkModeSwitch workModeSwitch = switchWeakReference.get();
|
||||
if (workModeSwitch == null || !Utilities.ATLEAST_P) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Context context = workModeSwitch.getContext();
|
||||
UserManager userManager = context.getSystemService(UserManager.class);
|
||||
boolean showConfirm = false;
|
||||
for (UserHandle userProfile : UserCache.INSTANCE.get(context).getUserProfiles()) {
|
||||
if (Process.myUserHandle().equals(userProfile)) {
|
||||
continue;
|
||||
}
|
||||
showConfirm |= !userManager.requestQuietModeEnabled(enabled, userProfile);
|
||||
}
|
||||
return showConfirm;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean showConfirm) {
|
||||
if (showConfirm) {
|
||||
WorkModeSwitch workModeSwitch = switchWeakReference.get();
|
||||
if (workModeSwitch != null) {
|
||||
workModeSwitch.setEnabled(true);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (Utilities.ATLEAST_P) {
|
||||
setEnabled(false);
|
||||
UI_HELPER_EXECUTOR.post(() -> setToState(!mWorkEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a work tip on the Nth work tab open
|
||||
* Sets the enabled or disabled state of the button
|
||||
*/
|
||||
public void showTipIfNeeded() {
|
||||
Context context = getContext();
|
||||
SharedPreferences prefs = Utilities.getPrefs(context);
|
||||
int tipCounter = prefs.getInt(KEY_WORK_TIP_COUNTER, WORK_TIP_THRESHOLD);
|
||||
if (tipCounter < 0) return;
|
||||
if (tipCounter == 0) {
|
||||
new ArrowTipView(context)
|
||||
.show(context.getString(R.string.work_switch_tip), getTop());
|
||||
public void updateCurrentState(boolean active) {
|
||||
mWorkEnabled = active;
|
||||
setEnabled(true);
|
||||
setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||
active ? R.drawable.ic_corp_off : R.drawable.ic_corp, 0, 0, 0);
|
||||
setText(active ? R.string.work_apps_pause_btn_text : R.string.work_apps_enable_btn_text);
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.P)
|
||||
protected Boolean setToState(boolean toState) {
|
||||
UserManager userManager = getContext().getSystemService(UserManager.class);
|
||||
boolean showConfirm = false;
|
||||
for (UserHandle userProfile : UserCache.INSTANCE.get(getContext()).getUserProfiles()) {
|
||||
if (Process.myUserHandle().equals(userProfile)) {
|
||||
continue;
|
||||
}
|
||||
showConfirm |= !userManager.requestQuietModeEnabled(!toState, userProfile);
|
||||
}
|
||||
prefs.edit().putInt(KEY_WORK_TIP_COUNTER, tipCounter - 1).apply();
|
||||
return showConfirm;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,230 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.views;
|
||||
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.allapps.AllAppsContainerView;
|
||||
import com.android.launcher3.allapps.AllAppsPagedView;
|
||||
import com.android.launcher3.anim.AnimationSuccessListener;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.statemanager.StateManager.StateListener;
|
||||
|
||||
/**
|
||||
* On boarding flow for users right after setting up work profile
|
||||
*/
|
||||
public class WorkEduView extends AbstractSlideInView<Launcher>
|
||||
implements Insettable, StateListener<LauncherState> {
|
||||
|
||||
private static final int DEFAULT_CLOSE_DURATION = 200;
|
||||
public static final String KEY_WORK_EDU_STEP = "showed_work_profile_edu";
|
||||
public static final String KEY_LEGACY_WORK_EDU_SEEN = "showed_bottom_user_education";
|
||||
|
||||
private static final int WORK_EDU_NOT_STARTED = 0;
|
||||
private static final int WORK_EDU_PERSONAL_APPS = 1;
|
||||
private static final int WORK_EDU_WORK_APPS = 2;
|
||||
|
||||
protected static final int FINAL_SCRIM_BG_COLOR = 0x88000000;
|
||||
|
||||
|
||||
private Rect mInsets = new Rect();
|
||||
private View mViewWrapper;
|
||||
private Button mProceedButton;
|
||||
private TextView mContentText;
|
||||
|
||||
private int mNextWorkEduStep = WORK_EDU_PERSONAL_APPS;
|
||||
|
||||
|
||||
public WorkEduView(Context context, AttributeSet attr) {
|
||||
this(context, attr, 0);
|
||||
}
|
||||
|
||||
public WorkEduView(Context context, AttributeSet attrs,
|
||||
int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mContent = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleClose(boolean animate) {
|
||||
mActivityContext.getSharedPrefs().edit()
|
||||
.putInt(KEY_WORK_EDU_STEP, mNextWorkEduStep).apply();
|
||||
handleClose(true, DEFAULT_CLOSE_DURATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCloseComplete() {
|
||||
super.onCloseComplete();
|
||||
mActivityContext.getStateManager().removeStateListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isOfType(int type) {
|
||||
return (type & TYPE_ON_BOARD_POPUP) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mViewWrapper = findViewById(R.id.view_wrapper);
|
||||
mProceedButton = findViewById(R.id.proceed);
|
||||
mContentText = findViewById(R.id.content_text);
|
||||
|
||||
// make sure layout does not shrink when we change the text
|
||||
mContentText.post(() -> mContentText.setMinLines(mContentText.getLineCount()));
|
||||
|
||||
mProceedButton.setOnClickListener(view -> {
|
||||
if (getAllAppsPagedView() != null) {
|
||||
getAllAppsPagedView().snapToPage(AllAppsContainerView.AdapterHolder.WORK);
|
||||
}
|
||||
goToWorkTab(true);
|
||||
});
|
||||
}
|
||||
|
||||
private void goToWorkTab(boolean animate) {
|
||||
mProceedButton.setText(R.string.work_profile_edu_accept);
|
||||
if (animate) {
|
||||
ObjectAnimator animator = ObjectAnimator.ofFloat(mContentText, ALPHA, 0);
|
||||
animator.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
mContentText.setText(
|
||||
mActivityContext.getString(R.string.work_profile_edu_work_apps));
|
||||
ObjectAnimator.ofFloat(mContentText, ALPHA, 1).start();
|
||||
}
|
||||
});
|
||||
animator.start();
|
||||
} else {
|
||||
mContentText.setText(mActivityContext.getString(R.string.work_profile_edu_work_apps));
|
||||
}
|
||||
mNextWorkEduStep = WORK_EDU_WORK_APPS;
|
||||
mProceedButton.setOnClickListener(v -> handleClose(true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInsets(Rect insets) {
|
||||
int leftInset = insets.left - mInsets.left;
|
||||
int rightInset = insets.right - mInsets.right;
|
||||
int bottomInset = insets.bottom - mInsets.bottom;
|
||||
mInsets.set(insets);
|
||||
setPadding(leftInset, getPaddingTop(), rightInset, 0);
|
||||
mViewWrapper.setPaddingRelative(mViewWrapper.getPaddingStart(),
|
||||
mViewWrapper.getPaddingTop(), mViewWrapper.getPaddingEnd(), bottomInset);
|
||||
}
|
||||
|
||||
private void show() {
|
||||
attachToContainer();
|
||||
animateOpen();
|
||||
mActivityContext.getStateManager().addStateListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getScrimColor(Context context) {
|
||||
return FINAL_SCRIM_BG_COLOR;
|
||||
}
|
||||
|
||||
private void goToFirstPage() {
|
||||
if (getAllAppsPagedView() != null) {
|
||||
getAllAppsPagedView().snapToPageImmediately(AllAppsContainerView.AdapterHolder.MAIN);
|
||||
}
|
||||
}
|
||||
|
||||
private void animateOpen() {
|
||||
if (mIsOpen || mOpenCloseAnimator.isRunning()) {
|
||||
return;
|
||||
}
|
||||
mIsOpen = true;
|
||||
mOpenCloseAnimator.setValues(
|
||||
PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
|
||||
mOpenCloseAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
|
||||
mOpenCloseAnimator.start();
|
||||
}
|
||||
|
||||
private AllAppsPagedView getAllAppsPagedView() {
|
||||
View v = mActivityContext.getAppsView().getContentView();
|
||||
return (v instanceof AllAppsPagedView) ? (AllAppsPagedView) v : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if user has not seen onboarding UI yet and shows it when user navigates to all apps
|
||||
*/
|
||||
public static StateListener<LauncherState> showEduFlowIfNeeded(Launcher launcher,
|
||||
@Nullable StateListener<LauncherState> oldListener) {
|
||||
if (oldListener != null) {
|
||||
launcher.getStateManager().removeStateListener(oldListener);
|
||||
}
|
||||
if (hasSeenLegacyEdu(launcher) || launcher.getSharedPrefs().getInt(KEY_WORK_EDU_STEP,
|
||||
WORK_EDU_NOT_STARTED) != WORK_EDU_NOT_STARTED) {
|
||||
return null;
|
||||
}
|
||||
|
||||
StateListener<LauncherState> listener = new StateListener<LauncherState>() {
|
||||
@Override
|
||||
public void onStateTransitionComplete(LauncherState finalState) {
|
||||
if (finalState != LauncherState.ALL_APPS) return;
|
||||
LayoutInflater layoutInflater = LayoutInflater.from(launcher);
|
||||
WorkEduView v = (WorkEduView) layoutInflater.inflate(
|
||||
R.layout.work_profile_edu, launcher.getDragLayer(),
|
||||
false);
|
||||
v.show();
|
||||
v.goToFirstPage();
|
||||
launcher.getStateManager().removeStateListener(this);
|
||||
}
|
||||
};
|
||||
launcher.getStateManager().addStateListener(listener);
|
||||
return listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows work apps edu if user had dismissed full edu flow
|
||||
*/
|
||||
public static void showWorkEduIfNeeded(Launcher launcher) {
|
||||
if (hasSeenLegacyEdu(launcher) || launcher.getSharedPrefs().getInt(KEY_WORK_EDU_STEP,
|
||||
WORK_EDU_NOT_STARTED) != WORK_EDU_PERSONAL_APPS) {
|
||||
return;
|
||||
}
|
||||
LayoutInflater layoutInflater = LayoutInflater.from(launcher);
|
||||
WorkEduView v = (WorkEduView) layoutInflater.inflate(
|
||||
R.layout.work_profile_edu, launcher.getDragLayer(), false);
|
||||
v.show();
|
||||
v.goToWorkTab(false);
|
||||
}
|
||||
|
||||
private static boolean hasSeenLegacyEdu(Launcher launcher) {
|
||||
return launcher.getSharedPrefs().getBoolean(KEY_LEGACY_WORK_EDU_SEEN, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateTransitionComplete(LauncherState finalState) {
|
||||
close(false);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue