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

Commit 917f1018 authored by Fan Zhang's avatar Fan Zhang
Browse files

Instantiate pref controllers from xml if it's defined.

- If a <preference> tag also defines a controller, we will try to
  instantiate it before displaying the UI. The same logic is shared by
  BaseSearchIndexProvider so it also drives search suppression.

- If user also defines a list of controllers programatically, the
  programatically created ones takes precedence.

Bug: 73668763
Test: WIP
Change-Id: I7aecec270bcd3af261e012ef1f6995d2a523cfa1
parent fc520ee3
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -4,6 +4,15 @@
# Keep all Fragments in this package, which are used by reflection.
-keep public class com.android.settings.** extends android.app.Fragment

# Keep all preference controllers needed by slice and DashboardFragment.
-keep class * extends com.android.settings.core.BasePreferenceController {
    *;
}

-keep class * extends com.android.settings.core.TogglePreferenceController {
    *;
}

# We want to keep methods in Activity that could be used in the XML attribute onClick.
-keepclassmembers class * extends android.app.Activity {
    public void *(android.view.View);
+6 −2
Original line number Diff line number Diff line
@@ -49,10 +49,14 @@ public class BluetoothDetailsMacAddressController extends BluetoothDetailsContro
    }

    @Override
    protected void refresh() {}
    protected void refresh() {
    }

    @Override
    public String getPreferenceKey() {
        if (mFooterPreference == null) {
            return null;
        }
        return mFooterPreference.getKey();
    }
}
+0 −8
Original line number Diff line number Diff line
@@ -119,15 +119,7 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment {

                @Override
                public List<String> getNonIndexableKeys(Context context) {

                    return new ArrayList<>();
                }

                @Override
                public List<AbstractPreferenceController> getPreferenceControllers(
                        Context context) {
                    //TODO(b/69333961): update the index for controllers
                    return super.getPreferenceControllers(context);
                }
            };
}
+3 −0
Original line number Diff line number Diff line
@@ -116,6 +116,9 @@ public abstract class BasePreferenceController extends AbstractPreferenceControl
    public BasePreferenceController(Context context, String preferenceKey) {
        super(context);
        mPreferenceKey = preferenceKey;
        if (TextUtils.isEmpty(mPreferenceKey)) {
            throw new IllegalArgumentException("Preference key must be set");
        }
    }

    /**
+117 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.core;

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

import android.annotation.NonNull;
import android.annotation.XmlRes;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;

import com.android.settingslib.core.AbstractPreferenceController;

import org.xmlpull.v1.XmlPullParserException;

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

/**
 * Helper to load {@link BasePreferenceController} lists from Xml.
 */
public class PreferenceControllerListHelper {

    private static final String TAG = "PrefCtrlListCreator";

    /**
     * Instantiates a list of controller based on xml definition.
     */
    @NonNull
    public static List<BasePreferenceController> getPreferenceControllersFromXml(Context context,
            @XmlRes int xmlResId) {
        final List<BasePreferenceController> controllers = new ArrayList<>();
        List<Bundle> preferenceMetadata;
        try {
            preferenceMetadata = PreferenceXmlParserUtils.extractMetadata(context, xmlResId);
        } catch (IOException | XmlPullParserException e) {
            Log.e(TAG, "Failed to parse preference xml for getting controllers");
            return controllers;
        }

        for (Bundle metadata : preferenceMetadata) {
            final String controllerName = metadata.getString(METADATA_CONTROLLER);
            if (TextUtils.isEmpty(controllerName)) {
                continue;
            }
            BasePreferenceController controller;
            try {
                controller = BasePreferenceController.createInstance(context, controllerName);
            } catch (IllegalStateException e) {
                final String key = metadata.getString(METADATA_KEY);
                if (TextUtils.isEmpty(key)) {
                    Log.w(TAG, "Controller requires key but it's not defined in xml: "
                            + controllerName);
                    continue;
                }
                Log.d(TAG, "Could not find Context-only controller for pref: " + key);
                controller = BasePreferenceController.createInstance(context, controllerName, key);
            }
            controllers.add(controller);
        }
        return controllers;
    }

    /**
     * Return a sub list of {@link AbstractPreferenceController} to only contain controller that
     * doesn't exist in filter.
     *
     * @param filter The filter. This list will be unchanged.
     * @param input  This list will be filtered into a sublist and element is kept
     *               IFF the controller key is not used by anything from {@param filter}.
     */
    @NonNull
    public static List<BasePreferenceController> filterControllers(
            @NonNull List<BasePreferenceController> input,
            List<AbstractPreferenceController> filter) {
        if (input == null || filter == null) {
            return input;
        }
        final Set<String> keys = new TreeSet<>();
        final List<BasePreferenceController> filteredList = new ArrayList<>();
        for (AbstractPreferenceController controller : filter) {
            final String key = controller.getPreferenceKey();
            if (key != null) {
                keys.add(key);
            }
        }
        for (BasePreferenceController controller : input) {
            if (keys.contains(controller.getPreferenceKey())) {
                Log.w(TAG, controller.getPreferenceKey() + " already has a controller");
                continue;
            }
            filteredList.add(controller);
        }
        return filteredList;
    }

}
Loading