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

Commit dd030ce7 authored by Hai Zhang's avatar Hai Zhang Committed by android-build-merger
Browse files

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

am: 22314aac

Change-Id: I552e2403b6b2fc4cec70acc0173c22cc4be69e8f
parents 2cfea049 22314aac
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