Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7d3a113d authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Work profile accessibility fixes" into ub-launcher3-master

parents b55d5b27 45c3b104
Loading
Loading
Loading
Loading
+16 −29
Original line number Diff line number Diff line
@@ -13,39 +13,26 @@
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<com.android.launcher3.views.WorkFooterContainer
<com.android.launcher3.allapps.WorkModeSwitch
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/work_toggle_container"
    android:focusable="true"
    android:orientation="horizontal"
    android:background="?attr/allAppsScrimColor"
    android:paddingBottom="@dimen/all_apps_work_profile_tab_footer_padding"
    android:paddingLeft="@dimen/all_apps_work_profile_tab_footer_padding"
    android:paddingRight="@dimen/all_apps_work_profile_tab_footer_padding"
    android:paddingTop="@dimen/all_apps_work_profile_tab_footer_padding">

    <TextView
    style="@style/PrimaryMediumText"
        android:id="@+id/work_mode_label"
        android:layout_width="0dp"
        android:layout_weight="1"
    android:id="@+id/work_mode_toggle"
    android:drawableStart="@drawable/ic_corp"
    android:drawablePadding="16dp"
    android:drawableTint="?attr/workProfileOverlayTextColor"
    android:textColor="?attr/workProfileOverlayTextColor"
        android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:ellipsize="end"
        android:gravity="center_vertical"
    android:gravity="start"
    android:lines="1"
        android:minHeight="24dp"
        android:paddingEnd="12dp"
    android:showText="false"
    android:textSize="16sp"
    android:background="?attr/allAppsScrimColor"
    android:text="@string/work_profile_toggle_label"
        android:textSize="16sp"/>
    <com.android.launcher3.allapps.WorkModeSwitch
        android:id="@+id/work_mode_toggle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</com.android.launcher3.views.WorkFooterContainer>
 No newline at end of file
    android:paddingBottom="@dimen/all_apps_work_profile_tab_footer_padding"
    android:paddingLeft="@dimen/all_apps_work_profile_tab_footer_padding"
    android:paddingRight="@dimen/all_apps_work_profile_tab_footer_padding"
    android:paddingTop="@dimen/all_apps_work_profile_tab_footer_padding"
/>
+17 −20
Original line number Diff line number Diff line
@@ -62,7 +62,6 @@ import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.SpringRelativeLayout;
import com.android.launcher3.views.WorkFooterContainer;

import java.util.ArrayList;

@@ -91,7 +90,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
    private AllAppsPagedView mViewPager;

    private FloatingHeaderView mHeader;
    private WorkFooterContainer mWorkFooterContainer;
    private WorkModeSwitch mWorkModeSwitch;


    private SpannableStringBuilder mSearchQueryBuilder = null;
@@ -156,8 +155,8 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
        return mMultiValueAlpha.getProperty(index);
    }

    public WorkFooterContainer getWorkFooterContainer() {
        return mWorkFooterContainer;
    public WorkModeSwitch getWorkModeSwitch() {
        return mWorkModeSwitch;
    }


@@ -195,7 +194,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
    }

    private void resetWorkProfile() {
        mWorkFooterContainer.refresh();
        mWorkModeSwitch.refresh();
        mAH[AdapterHolder.WORK].setupOverlay();
        mAH[AdapterHolder.WORK].applyPadding();
    }
@@ -410,9 +409,9 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
        } else {
            mAH[AdapterHolder.MAIN].setup(findViewById(R.id.apps_list_view), null);
            mAH[AdapterHolder.WORK].recyclerView = null;
            if (mWorkFooterContainer != null) {
                ((ViewGroup) mWorkFooterContainer.getParent()).removeView(mWorkFooterContainer);
                mWorkFooterContainer = null;
            if (mWorkModeSwitch != null) {
                ((ViewGroup) mWorkModeSwitch.getParent()).removeView(mWorkModeSwitch);
                mWorkModeSwitch = null;
            }
        }
        setupHeader();
@@ -422,14 +421,11 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
    }

    private void setupWorkToggle() {
        mWorkFooterContainer = (WorkFooterContainer) mLauncher.getLayoutInflater().inflate(
                R.layout.work_tab_footer, findViewById(R.id.work_toggle_container));
        mWorkFooterContainer.setLayoutParams(
                new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT));
        this.addView(mWorkFooterContainer);
        mWorkFooterContainer.setInsets(mInsets);
        mWorkFooterContainer.post(() -> mAH[AdapterHolder.WORK].applyPadding());
        mWorkModeSwitch = (WorkModeSwitch) mLauncher.getLayoutInflater().inflate(
                R.layout.work_mode_switch, this, false);
        this.addView(mWorkModeSwitch);
        mWorkModeSwitch.setInsets(mInsets);
        mWorkModeSwitch.post(() -> mAH[AdapterHolder.WORK].applyPadding());
    }

    private void replaceRVContainer(boolean showTabs) {
@@ -469,8 +465,8 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
            findViewById(R.id.tab_work)
                    .setOnClickListener((View view) -> mViewPager.snapToPage(AdapterHolder.WORK));
        }
        if (mWorkFooterContainer != null) {
            mWorkFooterContainer.setWorkTabVisible(pos == AdapterHolder.WORK);
        if (mWorkModeSwitch != null) {
            mWorkModeSwitch.setWorkTabVisible(pos == AdapterHolder.WORK);
        }
    }

@@ -648,6 +644,8 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
            if (!mIsWork || recyclerView == null) return;
            boolean workDisabled = UserCache.INSTANCE.get(mLauncher).isAnyProfileQuietModeEnabled();
            if (mWorkDisabled == workDisabled) return;
            recyclerView.setContentDescription(
                    workDisabled ? mLauncher.getString(R.string.work_apps_paused_title) : null);
            if (workDisabled) {
                appsList.updateItemFilter((info, cn) -> false);
                recyclerView.addAutoSizedOverlay(
@@ -662,8 +660,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
        void applyPadding() {
            if (recyclerView != null) {
                int bottomOffset =
                        mWorkFooterContainer != null && mIsWork ? mWorkFooterContainer.getHeight()
                                : 0;
                        mWorkModeSwitch != null && mIsWork ? mWorkModeSwitch.getHeight() : 0;
                recyclerView.setPadding(padding.left, padding.top, padding.right,
                        padding.bottom + bottomOffset);
            }
+60 −3
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 * 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.
@@ -15,7 +15,13 @@
 */
package com.android.launcher3.allapps;

import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;

import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.os.AsyncTask;
import android.os.Process;
import android.os.UserHandle;
@@ -24,28 +30,45 @@ import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Switch;

import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.pm.UserCache;

import java.lang.ref.WeakReference;

public class WorkModeSwitch extends Switch {
/**
 * Work profile toggle switch shown at the bottom of AllApps work tab
 */
public class WorkModeSwitch extends Switch implements Insettable {

    private Rect mInsets = new Rect();
    protected ObjectAnimator mOpenCloseAnimator;


    public WorkModeSwitch(Context context) {
        super(context);
        init();
    }

    public WorkModeSwitch(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public WorkModeSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mOpenCloseAnimator = ObjectAnimator.ofPropertyValuesHolder(this);
    }

    @Override
    public void setChecked(boolean checked) {
        // No-op, do not change the checked state until broadcast is received.

    }

    @Override
@@ -55,14 +78,23 @@ public class WorkModeSwitch extends Switch {

    private void setCheckedInternal(boolean checked) {
        super.setChecked(checked);
        setCompoundDrawablesWithIntrinsicBounds(
                checked ? R.drawable.ic_corp : R.drawable.ic_corp_off, 0, 0, 0);
    }

    public void refresh() {
        if (!shouldShowWorkSwitch()) return;
        UserCache userManager = UserCache.INSTANCE.get(getContext());
        setCheckedInternal(!userManager.isAnyProfileQuietModeEnabled());
        setEnabled(true);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        this.setVisibility(shouldShowWorkSwitch() ? VISIBLE : GONE);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return ev.getActionMasked() == MotionEvent.ACTION_MOVE || super.onTouchEvent(ev);
@@ -72,6 +104,24 @@ public class WorkModeSwitch extends Switch {
        new SetQuietModeEnabledAsyncTask(enabled, new WeakReference<>(this)).execute();
    }

    @Override
    public void setInsets(Rect insets) {
        int bottomInset = insets.bottom - mInsets.bottom;
        mInsets.set(insets);
        setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
                getPaddingBottom() + bottomInset);
    }

    /**
     * Animates in/out work profile toggle panel based on the tab user is on
     */
    public void setWorkTabVisible(boolean workTabVisible) {
        if (!shouldShowWorkSwitch()) return;

        mOpenCloseAnimator.setValues(PropertyValuesHolder.ofFloat(ALPHA, workTabVisible ? 1 : 0));
        mOpenCloseAnimator.start();
    }

    private static final class SetQuietModeEnabledAsyncTask
            extends AsyncTask<Void, Void, Boolean> {

@@ -122,4 +172,11 @@ public class WorkModeSwitch extends Switch {
            }
        }
    }

    private boolean shouldShowWorkSwitch() {
        Launcher launcher = Launcher.getLauncher(getContext());
        return Utilities.ATLEAST_P && (hasShortcutsPermission(launcher)
                || launcher.checkSelfPermission("android.permission.MODIFY_QUIET_MODE")
                == PackageManager.PERMISSION_GRANTED);
    }
}
+0 −133
Original line number Diff line number Diff line
/*
 * 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.
 */
package com.android.launcher3.views;

import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;

import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.WorkModeSwitch;
import com.android.launcher3.pm.UserCache;

/**
 * Container to show work footer in all-apps.
 */
public class WorkFooterContainer extends LinearLayout implements Insettable {
    private Rect mInsets = new Rect();

    private WorkModeSwitch mWorkModeSwitch;
    private TextView mWorkModeLabel;

    protected final ObjectAnimator mOpenCloseAnimator;

    public WorkFooterContainer(Context context) {
        this(context, null, 0);
    }

    public WorkFooterContainer(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WorkFooterContainer(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mOpenCloseAnimator = ObjectAnimator.ofPropertyValuesHolder(this);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        updateTranslation();
        this.setVisibility(shouldShowWorkFooter() ? VISIBLE : GONE);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mWorkModeSwitch = findViewById(R.id.work_mode_toggle);
        mWorkModeLabel = findViewById(R.id.work_mode_label);
    }

    @Override
    public void offsetTopAndBottom(int offset) {
        super.offsetTopAndBottom(offset);
        updateTranslation();
    }

    private void updateTranslation() {
        if (getParent() instanceof View) {
            View parent = (View) getParent();
            int availableBot = parent.getHeight() - parent.getPaddingBottom();
            setTranslationY(Math.max(0, availableBot - getBottom()));
        }
    }

    @Override
    public void setInsets(Rect insets) {
        int bottomInset = insets.bottom - mInsets.bottom;
        mInsets.set(insets);
        setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
                getPaddingBottom() + bottomInset);
    }

    /**
     * Animates in/out work profile toggle panel based on the tab user is on
     */
    public void setWorkTabVisible(boolean workTabVisible) {
        if (!shouldShowWorkFooter()) return;

        mOpenCloseAnimator.setValues(PropertyValuesHolder.ofFloat(ALPHA, workTabVisible ? 1 : 0));
        mOpenCloseAnimator.start();
    }

    /**
     * Refreshes views based on current work profile enabled status
     */
    public void refresh() {
        if (!shouldShowWorkFooter()) return;
        boolean anyProfileQuietModeEnabled = UserCache.INSTANCE.get(
                getContext()).isAnyProfileQuietModeEnabled();

        mWorkModeLabel.setCompoundDrawablesWithIntrinsicBounds(
                anyProfileQuietModeEnabled ? R.drawable.ic_corp_off : R.drawable.ic_corp, 0, 0, 0);
        mWorkModeSwitch.refresh();
    }

    /**
     * Returns work mode switch
     */
    public WorkModeSwitch getWorkModeSwitch() {
        return mWorkModeSwitch;
    }

    private boolean shouldShowWorkFooter() {
        Launcher launcher = Launcher.getLauncher(getContext());
        return Utilities.ATLEAST_P && (hasShortcutsPermission(launcher)
                || launcher.checkSelfPermission("android.permission.MODIFY_QUIET_MODE")
                == PackageManager.PERMISSION_GRANTED);
    }
}
+4 −4
Original line number Diff line number Diff line
@@ -31,9 +31,9 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsPagedView;
import com.android.launcher3.allapps.WorkModeSwitch;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.views.WorkEduView;
import com.android.launcher3.views.WorkFooterContainer;

import org.junit.After;
import org.junit.Before;
@@ -87,7 +87,7 @@ public class WorkTabTest extends AbstractLauncherUiTest {
        executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
        waitForState("Launcher internal state didn't switch to All Apps", () -> ALL_APPS);
        getOnceNotNull("Apps view did not bind",
                launcher -> launcher.getAppsView().getWorkFooterContainer(), 60000);
                launcher -> launcher.getAppsView().getWorkModeSwitch(), 60000);

        UserManager userManager = getFromLauncher(l -> l.getSystemService(UserManager.class));
        assertEquals(2, userManager.getUserProfiles().size());
@@ -102,10 +102,10 @@ public class WorkTabTest extends AbstractLauncherUiTest {

        assertTrue(userManager.isQuietModeEnabled(workProfile));
        executeOnLauncher(launcher -> {
            WorkFooterContainer wf = launcher.getAppsView().getWorkFooterContainer();
            WorkModeSwitch wf = launcher.getAppsView().getWorkModeSwitch();
            ((AllAppsPagedView) launcher.getAppsView().getContentView()).snapToPageImmediately(
                    AllAppsContainerView.AdapterHolder.WORK);
            wf.getWorkModeSwitch().toggle();
            wf.toggle();
        });
        waitForLauncherCondition("Work toggle did not work",
                l -> l.getSystemService(UserManager.class).isQuietModeEnabled(workProfile));