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

Commit b01d2410 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Gray out the "Remove account" button when there's a restriction" into main

parents ab4ee238 b6c2108c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <Button
    <com.android.settings.widget.RestrictedButton
        android:id="@+id/button"
        android:text="@string/remove_account_label"
        android:layout_width="wrap_content"
+12 −15
Original line number Diff line number Diff line
@@ -34,19 +34,17 @@ import android.os.UserManager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;

import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settings.widget.RestrictedButton;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.widget.LayoutPreference;
@@ -64,6 +62,7 @@ public class RemoveAccountPreferenceController extends AbstractPreferenceControl
    private Fragment mParentFragment;
    private UserHandle mUserHandle;
    private LayoutPreference mRemoveAccountPreference;
    private RestrictedButton mRemoveAccountButton;

    public RemoveAccountPreferenceController(Context context, Fragment parent) {
        super(context);
@@ -75,8 +74,14 @@ public class RemoveAccountPreferenceController extends AbstractPreferenceControl
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        mRemoveAccountPreference = screen.findPreference(KEY_REMOVE_ACCOUNT);
        final Button removeAccountButton = mRemoveAccountPreference.findViewById(R.id.button);
        removeAccountButton.setOnClickListener(this);
        mRemoveAccountButton = mRemoveAccountPreference.findViewById(R.id.button);
        mRemoveAccountButton.setOnClickListener(this);
    }

    @Override
    public void updateState(Preference preference) {
        super.updateState(preference);
        mRemoveAccountButton.updateState();
    }

    @Override
@@ -93,21 +98,13 @@ public class RemoveAccountPreferenceController extends AbstractPreferenceControl
    public void onClick(View v) {
        mMetricsFeatureProvider.logClickedPreference(mRemoveAccountPreference,
                mMetricsFeatureProvider.getMetricsCategory(mParentFragment));
        if (mUserHandle != null) {
            final EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
                    mContext, UserManager.DISALLOW_MODIFY_ACCOUNTS, mUserHandle.getIdentifier());
            if (admin != null) {
                RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, admin);
                return;
            }
        }

        ConfirmRemoveAccountDialog.show(mParentFragment, mAccount, mUserHandle);
    }

    public void init(Account account, UserHandle userHandle) {
        mAccount = account;
        mUserHandle = userHandle;
        mRemoveAccountButton.init(mUserHandle, UserManager.DISALLOW_MODIFY_ACCOUNTS);
    }

    /**
+86 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.settings.widget;

import android.content.Context;
import android.os.UserHandle;
import android.util.AttributeSet;
import android.widget.Button;

import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedLockUtilsInternal;

/**
 * A preference with a plus button on the side representing an "add" action. The plus button will
 * only be visible when a non-null click listener is registered.
 */
public class RestrictedButton extends Button {

    private UserHandle mUserHandle;
    private String mUserRestriction;

    public RestrictedButton(Context context) {
        super(context);
    }

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

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

    public RestrictedButton(Context context, AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean performClick() {
        EnforcedAdmin admin = getEnforcedAdmin();
        if (admin != null) {
            RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, admin);
            return false;
        }
        return super.performClick();
    }

    /** Initialize the button with {@link UserHandle} and a restriction */
    public void init(UserHandle userHandle, String restriction) {
        setAllowClickWhenDisabled(true);
        mUserHandle = userHandle;
        mUserRestriction = restriction;
    }

    /** Update the restriction state */
    public void updateState() {
        setEnabled(getEnforcedAdmin() == null);
    }

    private EnforcedAdmin getEnforcedAdmin() {
        if (mUserHandle != null) {
            EnforcedAdmin admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
                    mContext, mUserRestriction, mUserHandle.getIdentifier());
            if (admin != null) {
                return admin;
            }
        }
        return null;
    }
}
+2 −33
Original line number Diff line number Diff line
@@ -35,13 +35,10 @@ import android.accounts.AuthenticatorDescription;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
import android.widget.Button;

import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
@@ -57,11 +54,11 @@ import com.android.settings.testutils.shadow.ShadowDevicePolicyManager;
import com.android.settings.testutils.shadow.ShadowFragment;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.utils.ActivityControllerWrapper;
import com.android.settings.widget.RestrictedButton;
import com.android.settingslib.widget.LayoutPreference;

import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -74,8 +71,6 @@ import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
@@ -129,7 +124,7 @@ public class RemoveAccountPreferenceControllerTest {
    @Test
    public void displayPreference_shouldAddClickListener() {
        when(mScreen.findPreference(KEY_REMOVE_ACCOUNT)).thenReturn(mPreference);
        final Button button = mock(Button.class);
        final RestrictedButton button = mock(RestrictedButton.class);
        when(mPreference.findViewById(R.id.button)).thenReturn(button);

        mController.displayPreference(mScreen);
@@ -147,32 +142,6 @@ public class RemoveAccountPreferenceControllerTest {
                eq(TAG_REMOVE_ACCOUNT_DIALOG));
    }

    @Ignore
    @Test
    public void onClick_modifyAccountsIsDisallowed_shouldNotStartConfirmDialog() {
        when(mFragment.isAdded()).thenReturn(true);

        final int userId = UserHandle.myUserId();
        mController.init(new Account("test", "test"), UserHandle.of(userId));

        List<UserManager.EnforcingUser> enforcingUsers = new ArrayList<>();
        enforcingUsers.add(new UserManager.EnforcingUser(userId,
                UserManager.RESTRICTION_SOURCE_DEVICE_OWNER));
        ComponentName componentName = new ComponentName("test", "test");
        // Ensure that RestrictedLockUtils.checkIfRestrictionEnforced doesn't return null.
        ShadowUserManager.getShadow().setUserRestrictionSources(
                UserManager.DISALLOW_MODIFY_ACCOUNTS,
                UserHandle.of(userId),
                enforcingUsers);
        ShadowDevicePolicyManager.getShadow().setDeviceOwnerComponentOnAnyUser(componentName);

        mController.onClick(null);

        verify(mFragmentTransaction, never()).add(
                any(RemoveAccountPreferenceController.ConfirmRemoveAccountDialog.class),
                eq(TAG_REMOVE_ACCOUNT_DIALOG));
    }

    @Test
    @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class,
            ShadowFragment.class})
+12 −2
Original line number Diff line number Diff line
@@ -2,18 +2,22 @@ package com.android.settings.testutils.shadow;

import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
import static android.os.Build.VERSION_CODES.O;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManager.DeviceOwnerType;
import android.app.admin.IDevicePolicyManager;
import android.app.admin.ManagedSubscriptionsPolicy;
import android.app.admin.PasswordMetrics;
import android.app.admin.PasswordPolicy;
import android.content.ComponentName;
import android.content.Context;

import androidx.test.core.app.ApplicationProvider;

import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadow.api.Shadow;
@@ -39,6 +43,11 @@ public class ShadowDevicePolicyManager extends org.robolectric.shadows.ShadowDev

    private List<String> mPermittedAccessibilityServices = null;

    @Implementation(minSdk = O)
    protected void __constructor__(Context context, IDevicePolicyManager service) {
        super.__constructor__(ApplicationProvider.getApplicationContext(), service);
    }

    public void setShortSupportMessageForUser(ComponentName admin, int userHandle, String message) {
        mSupportMessagesMap.put(Objects.hash(admin, userHandle), message);
    }
@@ -137,6 +146,7 @@ public class ShadowDevicePolicyManager extends org.robolectric.shadows.ShadowDev

    public static ShadowDevicePolicyManager getShadow() {
        return (ShadowDevicePolicyManager) Shadow.extract(
                RuntimeEnvironment.application.getSystemService(DevicePolicyManager.class));
                ApplicationProvider.getApplicationContext()
                        .getSystemService(DevicePolicyManager.class));
    }
}
Loading