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

Commit f71db730 authored by Raff Tsai's avatar Raff Tsai
Browse files

Implement work-profile infra in BasePreferenceController

- Add settings:forWork in xml
- Set mIsForWork based on xml attribute
- Delete WorkProfilePreferenceController and move its function to
BasePreferenceController

Fixes: 123376083
Test: Add work profile, go to Settings->System->Language&input,
UI should show work profile related items
Change-Id: Id2dcbb0e158c117cdfd363466a275f4e133c345e
parent 9700435b
Loading
Loading
Loading
Loading
+3 −5
Original line number Diff line number Diff line
@@ -68,8 +68,10 @@
        <attr name="searchable" format="boolean" />
        <!-- Classname of a PreferenceController corresponding to the preference -->
        <attr name="controller" format="string" />
        <!-- customized subtitle if it's an unavailable slice -->
        <!-- Customized subtitle if it's an unavailable slice -->
        <attr name="unavailableSliceSubtitle" format="string" />
        <!-- Whether or not the preference is for work profile, by default it's false. -->
        <attr name="forWork" format="boolean" />
    </declare-styleable>

    <declare-styleable name="PreferenceScreen">
@@ -112,10 +114,6 @@
    <attr name="confirmDeviceCredentialsSideMargin" format="dimension" />
    <attr name="confirmDeviceCredentialsTopMargin" format="dimension" />

    <declare-styleable name="WorkPreference">
        <attr name="forWork" format="boolean" />
    </declare-styleable>

    <declare-styleable name="VideoPreference">
        <attr name="animation" format="reference" />
        <attr name="preview" format="reference" />
+3 −0
Original line number Diff line number Diff line
@@ -101,18 +101,21 @@
            android:key="virtual_keyboards_for_work_pref"
            android:title="@string/virtual_keyboards_for_work_title"
            android:fragment="com.android.settings.inputmethod.VirtualKeyboardFragment"
            settings:forWork="true"
            settings:controller="com.android.settings.inputmethod.VirtualKeyboardForWorkPreferenceController" />

        <Preference
            android:key="spellcheckers_settings_for_work_pref"
            android:title="@string/spellcheckers_settings_for_work_title"
            android:fragment="com.android.settings.inputmethod.SpellCheckersSettings"
            settings:forWork="true"
            settings:controller="com.android.settings.language.UserDictionaryForWorkPreferenceController" />

        <Preference
            android:key="user_dictionary_settings_for_work_pref"
            android:title="@string/user_dict_settings_for_work_title"
            android:fragment="com.android.settings.inputmethod.UserDictionaryList"
            settings:forWork="true"
            settings:controller="com.android.settings.inputmethod.SpellCheckerForWorkPreferenceController" />
    </com.android.settings.widget.WorkOnlyCategory>

+2 −0
Original line number Diff line number Diff line
@@ -62,6 +62,7 @@
            android:selectable="true"
            android:title="@string/managed_profile_location_switch_title"
            settings:controller="com.android.settings.location.LocationForWorkPreferenceController"
            settings:forWork="true"
            settings:useAdminDisabledSummary="true"/>

        <PreferenceCategory
@@ -73,6 +74,7 @@
        <PreferenceCategory
            android:key="location_services_managed_profile"
            android:title="@string/managed_profile_location_services"
            settings:forWork="true"
            settings:controller="com.android.settings.location.LocationServiceForWorkPreferenceController"/>

    </PreferenceCategory>
+92 −2
Original line number Diff line number Diff line
@@ -13,17 +13,24 @@
 */
package com.android.settings.core;

import static com.android.settings.dashboard.DashboardFragment.CATEGORY;

import android.annotation.IntDef;
import android.app.settings.SettingsEnums;
import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.SettingsSlicesContract;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;

import com.android.settings.Utils;
import com.android.settings.slices.SettingsSliceProvider;
import com.android.settings.slices.SliceData;
import com.android.settings.slices.Sliceable;
@@ -109,9 +116,11 @@ public abstract class BasePreferenceController extends AbstractPreferenceControl
     */
    public static final int DISABLED_DEPENDENT_SETTING = 5;


    protected final String mPreferenceKey;
    protected UiBlockListener mUiBlockListener;
    private boolean mIsForWork;
    @Nullable
    private UserHandle mWorkProfileUser;

    /**
     * Instantiate a controller as specified controller type and user-defined key.
@@ -151,6 +160,34 @@ public abstract class BasePreferenceController extends AbstractPreferenceControl
        }
    }

    /**
     * Instantiate a controller as specified controller type and work profile
     * <p/>
     * This is done through reflection. Do not use this method unless you know what you are doing.
     *
     * @param context        application context
     * @param controllerName class name of the {@link BasePreferenceController}
     * @param key            attribute android:key of the {@link Preference}
     * @param isWorkProfile  is this controller only for work profile user?
     */
    public static BasePreferenceController createInstance(Context context, String controllerName,
            String key, boolean isWorkProfile) {
        try {
            final Class<?> clazz = Class.forName(controllerName);
            final Constructor<?> preferenceConstructor =
                    clazz.getConstructor(Context.class, String.class);
            final Object[] params = new Object[]{context, key};
            final BasePreferenceController controller =
                    (BasePreferenceController) preferenceConstructor.newInstance(params);
            controller.setForWork(isWorkProfile);
            return controller;
        } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException
                | IllegalArgumentException | InvocationTargetException | IllegalAccessException e) {
            throw new IllegalStateException(
                    "Invalid preference controller: " + controllerName, e);
        }
    }

    public BasePreferenceController(Context context, String preferenceKey) {
        super(context);
        mPreferenceKey = preferenceKey;
@@ -166,6 +203,9 @@ public abstract class BasePreferenceController extends AbstractPreferenceControl
     * </p>
     * The status is used for the convenience methods: {@link #isAvailable()},
     * {@link #isSupported()}
     * </p>
     * The inherited class doesn't need to check work profile is existed or not if
     * android:forWork="true" is set in preference xml.
     */
    @AvailabilityStatus
    public abstract int getAvailabilityStatus();
@@ -198,12 +238,18 @@ public abstract class BasePreferenceController extends AbstractPreferenceControl
     * {@link #DISABLED_DEPENDENT_SETTING}, then the setting will be disabled by default in the
     * DashboardFragment, and it is up to the {@link BasePreferenceController} to enable the
     * preference at the right time.
     *
     * <p>
     * This function also check if work profile is existed when android:forWork="true" is set for
     * the controller in preference xml.
     * TODO (mfritze) Build a dependency mechanism to allow a controller to easily define the
     * dependent setting.
     */
    @Override
    public final boolean isAvailable() {
        if (mIsForWork && mWorkProfileUser == null) {
            return false;
        }

        final int availabilityStatus = getAvailabilityStatus();
        return (availabilityStatus == AVAILABLE
                || availabilityStatus == AVAILABLE_UNSEARCHABLE
@@ -266,6 +312,41 @@ public abstract class BasePreferenceController extends AbstractPreferenceControl
        }
    }

    /**
     * Indicates this controller is only for work profile user
     */
    void setForWork(boolean forWork) {
        mIsForWork = forWork;
        if (mIsForWork) {
            mWorkProfileUser = Utils.getManagedProfile(UserManager.get(mContext));
        }
    }

    /**
     * Launches the specified fragment for the work profile user if the associated
     * {@link Preference} is clicked.  Otherwise just forward it to the super class.
     *
     * @param preference the preference being clicked.
     * @return {@code true} if handled.
     */
    @Override
    public boolean handlePreferenceTreeClick(Preference preference) {
        if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
            return super.handlePreferenceTreeClick(preference);
        }
        if (!mIsForWork || mWorkProfileUser == null) {
            return super.handlePreferenceTreeClick(preference);
        }
        new SubSettingLauncher(preference.getContext())
                .setDestination(preference.getFragment())
                .setSourceMetricsCategory(preference.getExtras().getInt(CATEGORY,
                        SettingsEnums.PAGE_UNKNOWN))
                .setArguments(preference.getExtras())
                .setUserHandle(mWorkProfileUser)
                .launch();
        return true;
    }

    /**
     * Updates raw data for search provider.
     *
@@ -316,4 +397,13 @@ public abstract class BasePreferenceController extends AbstractPreferenceControl
     */
    public interface UiBlocker {
    }

    /**
     * @return Non-{@code null} {@link UserHandle} when a work profile is enabled.
     * Otherwise {@code null}.
     */
    @Nullable
    protected UserHandle getWorkProfileUser() {
        return mWorkProfileUser;
    }
}
+4 −2
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.settings.core;

import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_CONTROLLER;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_FOR_WORK;
import static com.android.settings.core.PreferenceXmlParserUtils.METADATA_KEY;

import android.annotation.NonNull;
@@ -55,7 +56,7 @@ public class PreferenceControllerListHelper {
        try {
            preferenceMetadata = PreferenceXmlParserUtils.extractMetadata(context, xmlResId,
                    MetadataFlag.FLAG_NEED_KEY | MetadataFlag.FLAG_NEED_PREF_CONTROLLER
                            | MetadataFlag.FLAG_INCLUDE_PREF_SCREEN);
                            | MetadataFlag.FLAG_INCLUDE_PREF_SCREEN  | MetadataFlag.FLAG_FOR_WORK);
        } catch (IOException | XmlPullParserException e) {
            Log.e(TAG, "Failed to parse preference xml for getting controllers", e);
            return controllers;
@@ -72,6 +73,7 @@ public class PreferenceControllerListHelper {
            } catch (IllegalStateException e) {
                Log.d(TAG, "Could not find Context-only controller for pref: " + controllerName);
                final String key = metadata.getString(METADATA_KEY);
                final boolean isWorkProfile = metadata.getBoolean(METADATA_FOR_WORK, false);
                if (TextUtils.isEmpty(key)) {
                    Log.w(TAG, "Controller requires key but it's not defined in xml: "
                            + controllerName);
@@ -79,7 +81,7 @@ public class PreferenceControllerListHelper {
                }
                try {
                    controller = BasePreferenceController.createInstance(context, controllerName,
                            key);
                            key, isWorkProfile);
                } catch (IllegalStateException e2) {
                    Log.w(TAG, "Cannot instantiate controller from reflection: " + controllerName);
                    continue;
Loading