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

Commit 22314aac authored by Hai Zhang's avatar Hai Zhang Committed by Android (Google) Code Review
Browse files

Merge "Separate preference inflation and impl for special app access settings." into qt-dev

parents 7f409acf 4839ce14
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -194,7 +194,7 @@ public class DefaultAppListChildFragment<PF extends PreferenceFragmentCompat
        UserHandle user = preference.getExtras().getParcelable(Intent.EXTRA_USER);
        Intent intent = role.getManageIntentAsUser(user, context);
        if (intent == null) {
            intent = DefaultAppActivity.createIntent(roleName, user, requireContext());
            intent = DefaultAppActivity.createIntent(roleName, user, context);
        }
        startActivity(intent);
        return true;
@@ -271,11 +271,11 @@ public class DefaultAppListChildFragment<PF extends PreferenceFragmentCompat
    public interface Parent {

        /**
         * Create a new preference for a role.
         * Create a new preference for a default app.
         *
         * @param context the {@code Context} to use when creating the preference.
         *
         * @return a new preference for a role
         * @return a new preference for a default app
         */
        @NonNull
        TwoTargetPreference createPreference(@NonNull Context context);
+3 −1
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import androidx.fragment.app.FragmentActivity;

import com.android.packageinstaller.role.model.Role;
import com.android.packageinstaller.role.model.Roles;
import com.android.packageinstaller.role.ui.handheld.HandheldSpecialAppAccessFragment;

/**
 * Activity for a special app access.
@@ -77,7 +78,8 @@ public class SpecialAppAccessActivity extends FragmentActivity {
        }

        if (savedInstanceState == null) {
            SpecialAppAccessFragment fragment = SpecialAppAccessFragment.newInstance(roleName);
            HandheldSpecialAppAccessFragment fragment =
                    HandheldSpecialAppAccessFragment.newInstance(roleName);
            getSupportFragmentManager().beginTransaction()
                    .add(android.R.id.content, fragment)
                    .commit();
+72 −39
Original line number Diff line number Diff line
@@ -23,40 +23,39 @@ import android.content.pm.ApplicationInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProviders;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.TwoStatePreference;

import com.android.packageinstaller.permission.utils.Utils;
import com.android.packageinstaller.role.model.Role;
import com.android.packageinstaller.role.model.Roles;
import com.android.packageinstaller.role.ui.handheld.AppIconSwitchPreference;
import com.android.packageinstaller.role.ui.handheld.FooterPreference;
import com.android.packageinstaller.role.ui.handheld.SettingsFragment;
import com.android.permissioncontroller.R;

import java.util.List;

/**
 * Fragment for a special app access.
 * Child fragment for a special app access. Must be added as a child fragment and its parent
 * fragment must be a {@link PreferenceFragmentCompat} which implements {@link Parent}.
 *
 * @param <PF> type of the parent fragment
 */
public class SpecialAppAccessFragment extends SettingsFragment
public class SpecialAppAccessChildFragment<PF extends PreferenceFragmentCompat
        & SpecialAppAccessChildFragment.Parent> extends Fragment
        implements Preference.OnPreferenceClickListener {

    private static final String LOG_TAG = SpecialAppAccessFragment.class.getSimpleName();

    private static final String PREFERENCE_EXTRA_APPLICATION_INFO =
            SpecialAppAccessFragment.class.getName() + ".extra.APPLICATION_INFO";
            SpecialAppAccessChildFragment.class.getName() + ".extra.APPLICATION_INFO";

    private static final String PREFERENCE_KEY_DESCRIPTION =
            SpecialAppAccessFragment.class.getName() + ".preference.DESCRIPTION";
            SpecialAppAccessChildFragment.class.getName() + ".preference.DESCRIPTION";

    private String mRoleName;

@@ -72,8 +71,8 @@ public class SpecialAppAccessFragment extends SettingsFragment
     * @return a new instance of this fragment
     */
    @NonNull
    public static SpecialAppAccessFragment newInstance(@NonNull String roleName) {
        SpecialAppAccessFragment fragment = new SpecialAppAccessFragment();
    public static SpecialAppAccessChildFragment newInstance(@NonNull String roleName) {
        SpecialAppAccessChildFragment fragment = new SpecialAppAccessChildFragment();
        Bundle arguments = new Bundle();
        arguments.putString(Intent.EXTRA_ROLE_NAME, roleName);
        fragment.setArguments(arguments);
@@ -92,9 +91,10 @@ public class SpecialAppAccessFragment extends SettingsFragment
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        PF preferenceFragment = requirePreferenceFragment();
        Activity activity = requireActivity();
        mRole = Roles.get(activity).get(mRoleName);
        activity.setTitle(mRole.getLabelResource());
        preferenceFragment.setTitle(getString(mRole.getLabelResource()));

        mViewModel = ViewModelProviders.of(this, new SpecialAppAccessViewModel.Factory(mRole,
                activity.getApplication())).get(SpecialAppAccessViewModel.class);
@@ -102,23 +102,18 @@ public class SpecialAppAccessFragment extends SettingsFragment
        mViewModel.observeManageRoleHolderState(this, this::onManageRoleHolderStateChanged);
    }

    @Override
    @StringRes
    protected int getEmptyTextResource() {
        return R.string.special_app_access_no_apps;
    }

    private void onRoleChanged(
            @NonNull List<Pair<ApplicationInfo, Boolean>> qualifyingApplications) {
        PreferenceManager preferenceManager = getPreferenceManager();
        PF preferenceFragment = requirePreferenceFragment();
        PreferenceManager preferenceManager = preferenceFragment.getPreferenceManager();
        Context context = preferenceManager.getContext();

        PreferenceScreen preferenceScreen = getPreferenceScreen();
        PreferenceScreen preferenceScreen = preferenceFragment.getPreferenceScreen();
        Preference oldDescriptionPreference = null;
        ArrayMap<String, Preference> oldPreferences = new ArrayMap<>();
        if (preferenceScreen == null) {
            preferenceScreen = preferenceManager.createPreferenceScreen(context);
            setPreferenceScreen(preferenceScreen);
            preferenceFragment.setPreferenceScreen(preferenceScreen);
        } else {
            oldDescriptionPreference = preferenceScreen.findPreference(PREFERENCE_KEY_DESCRIPTION);
            for (int i = preferenceScreen.getPreferenceCount() - 1; i >= 0; --i) {
@@ -137,10 +132,9 @@ public class SpecialAppAccessFragment extends SettingsFragment

            String key = qualifyingApplicationInfo.packageName + '_'
                    + qualifyingApplicationInfo.uid;
            AppIconSwitchPreference preference = (AppIconSwitchPreference) oldPreferences.get(
                    key);
            TwoStatePreference preference = (TwoStatePreference) oldPreferences.get(key);
            if (preference == null) {
                preference = new AppIconSwitchPreference(context);
                preference = preferenceFragment.createApplicationPreference(context);
                preference.setKey(key);
                preference.setIcon(Utils.getBadgedIcon(context, qualifyingApplicationInfo));
                preference.setTitle(Utils.getAppLabel(qualifyingApplicationInfo, context));
@@ -161,13 +155,13 @@ public class SpecialAppAccessFragment extends SettingsFragment

        Preference descriptionPreference = oldDescriptionPreference;
        if (descriptionPreference == null) {
            descriptionPreference = new FooterPreference(context);
            descriptionPreference = preferenceFragment.createFooterPreference(context);
            descriptionPreference.setKey(PREFERENCE_KEY_DESCRIPTION);
            descriptionPreference.setSummary(mRole.getDescriptionResource());
        }
        preferenceScreen.addPreference(descriptionPreference);

        updateState();
        preferenceFragment.onPreferenceScreenChanged();
    }

    private void onManageRoleHolderStateChanged(@NonNull ManageRoleHolderStateLiveData liveData,
@@ -190,20 +184,59 @@ public class SpecialAppAccessFragment extends SettingsFragment

    @Override
    public boolean onPreferenceClick(@NonNull Preference preference) {
        String key = preference.getKey();
        ManageRoleHolderStateLiveData liveData = mViewModel.getManageRoleHolderStateLiveData(key,
                this);
        if (liveData.getValue() != ManageRoleHolderStateLiveData.STATE_IDLE) {
            Log.i(LOG_TAG, "Trying to set special app access while another request is on-going");
            return true;
        }

        ApplicationInfo applicationInfo = preference.getExtras().getParcelable(
                PREFERENCE_EXTRA_APPLICATION_INFO);
        String packageName = applicationInfo.packageName;
        UserHandle user = UserHandle.getUserHandleForUid(applicationInfo.uid);
        boolean add = !((AppIconSwitchPreference) preference).isChecked();
        liveData.setRoleHolderAsUser(mRoleName, packageName, add, 0, user, requireContext());
        boolean allow = !((TwoStatePreference) preference).isChecked();
        String key = preference.getKey();
        mViewModel.setSpecialAppAccessAsUser(packageName, allow, user, key, this,
                this::onManageRoleHolderStateChanged);
        return true;
    }

    @NonNull
    private PF requirePreferenceFragment() {
        //noinspection unchecked
        return (PF) requireParentFragment();
    }

    /**
     * Interface that the parent fragment must implement.
     */
    public interface Parent {

        /**
         * Set the title of the current settings page.
         *
         * @param title the title of the current settings page
         */
        void setTitle(@NonNull CharSequence title);

        /**
         * Create a new preference for an application.
         *
         * @param context the {@code Context} to use when creating the preference.
         *
         * @return a new preference for an application
         */
        @NonNull
        TwoStatePreference createApplicationPreference(@NonNull Context context);

        /**
         * Create a new preference for the footer.
         *
         * @param context the {@code Context} to use when creating the preference.
         *
         * @return a new preference for the footer
         */
        @NonNull
        Preference createFooterPreference(@NonNull Context context);

        /**
         * Callback when changes have been made to the {@link PreferenceScreen} of the parent
         * {@link PreferenceFragmentCompat}.
         */
        void onPreferenceScreenChanged();
    }
}
+4 −1
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import android.view.WindowManager;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;

import com.android.packageinstaller.role.ui.handheld.HandheldSpecialAppAccessListFragment;

/**
 * Activity for the list of special app accesses.
 */
@@ -35,7 +37,8 @@ public class SpecialAppAccessListActivity extends FragmentActivity {
                WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);

        if (savedInstanceState == null) {
            SpecialAppAccessListFragment fragment = SpecialAppAccessListFragment.newInstance();
            HandheldSpecialAppAccessListFragment fragment =
                    HandheldSpecialAppAccessListFragment.newInstance();
            getSupportFragmentManager().beginTransaction()
                    .add(android.R.id.content, fragment)
                    .commit();
+47 −29
Original line number Diff line number Diff line
@@ -25,28 +25,28 @@ import android.util.ArrayMap;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProviders;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;

import com.android.packageinstaller.role.model.Role;
import com.android.packageinstaller.role.model.Roles;
import com.android.packageinstaller.role.ui.handheld.AppIconSettingsButtonPreference;
import com.android.packageinstaller.role.ui.handheld.SettingsFragment;
import com.android.permissioncontroller.R;

import java.util.List;

/**
 * Fragment for the list of special app accesses.
 * Child fragment for the list of special app accesses. Must be added as a child fragment and its
 * parent fragment must be a {@link PreferenceFragmentCompat} which implements {@link Parent}.
 *
 * @param <PF> type of the parent fragment
 */
public class SpecialAppAccessListFragment extends SettingsFragment
public class SpecialAppAccessListChildFragment<PF extends PreferenceFragmentCompat
        & SpecialAppAccessListChildFragment.Parent> extends Fragment
        implements Preference.OnPreferenceClickListener {

    private static final String LOG_TAG = SpecialAppAccessListFragment.class.getSimpleName();

    private SpecialAppAccessListViewModel mViewModel;

    /**
@@ -55,8 +55,8 @@ public class SpecialAppAccessListFragment extends SettingsFragment
     * @return a new instance of this fragment
     */
    @NonNull
    public static SpecialAppAccessListFragment newInstance() {
        return new SpecialAppAccessListFragment();
    public static SpecialAppAccessListChildFragment newInstance() {
        return new SpecialAppAccessListChildFragment();
    }

    @Override
@@ -67,30 +67,20 @@ public class SpecialAppAccessListFragment extends SettingsFragment
        mViewModel.getLiveData().observe(this, roleItems -> onRoleListChanged());
    }

    @Override
    @StringRes
    protected int getEmptyTextResource() {
        return R.string.no_special_app_access;
    }

    @Override
    protected int getHelpUriResource() {
        return R.string.help_uri_special_app_access;
    }

    private void onRoleListChanged() {
        List<RoleItem> roleItems = mViewModel.getLiveData().getValue();
        if (roleItems == null) {
            return;
        }

        PreferenceManager preferenceManager = getPreferenceManager();
        PF preferenceFragment = requirePreferenceFragment();
        PreferenceManager preferenceManager = preferenceFragment.getPreferenceManager();
        Context context = preferenceManager.getContext();
        PreferenceScreen preferenceScreen = getPreferenceScreen();
        PreferenceScreen preferenceScreen = preferenceFragment.getPreferenceScreen();
        ArrayMap<String, Preference> oldPreferences = new ArrayMap<>();
        if (preferenceScreen == null) {
            preferenceScreen = preferenceManager.createPreferenceScreen(context);
            setPreferenceScreen(preferenceScreen);
            preferenceFragment.setPreferenceScreen(preferenceScreen);
        } else {
            for (int i = preferenceScreen.getPreferenceCount() - 1; i >= 0; --i) {
                Preference preference = preferenceScreen.getPreference(i);
@@ -104,10 +94,10 @@ public class SpecialAppAccessListFragment extends SettingsFragment
            RoleItem roleItem = roleItems.get(i);

            Role role = roleItem.getRole();
            AppIconSettingsButtonPreference preference =
                    (AppIconSettingsButtonPreference) oldPreferences.get(role.getName());
            TwoTargetPreference preference = (TwoTargetPreference) oldPreferences.get(
                    role.getName());
            if (preference == null) {
                preference = new AppIconSettingsButtonPreference(context);
                preference = preferenceFragment.createPreference(context);
                preference.setKey(role.getName());
                preference.setIconSpaceReserved(true);
                preference.setTitle(role.getShortLabelResource());
@@ -120,7 +110,7 @@ public class SpecialAppAccessListFragment extends SettingsFragment
            preferenceScreen.addPreference(preference);
        }

        updateState();
        preferenceFragment.onPreferenceScreenChanged();
    }

    @Override
@@ -131,9 +121,37 @@ public class SpecialAppAccessListFragment extends SettingsFragment
        UserHandle user = Process.myUserHandle();
        Intent intent = role.getManageIntentAsUser(user, context);
        if (intent == null) {
            intent = SpecialAppAccessActivity.createIntent(roleName, requireContext());
            intent = SpecialAppAccessActivity.createIntent(roleName, context);
        }
        startActivity(intent);
        return true;
    }

    @NonNull
    private PF requirePreferenceFragment() {
        //noinspection unchecked
        return (PF) requireParentFragment();
    }

    /**
     * Interface that the parent fragment must implement.
     */
    public interface Parent {

        /**
         * Create a new preference for a special app access.
         *
         * @param context the {@code Context} to use when creating the preference.
         *
         * @return a new preference for a special app access
         */
        @NonNull
        TwoTargetPreference createPreference(@NonNull Context context);

        /**
         * Callback when changes have been made to the {@link PreferenceScreen} of the parent
         * {@link PreferenceFragmentCompat}.
         */
        void onPreferenceScreenChanged();
    }
}
Loading