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

Commit 79d5428c authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Enable overlays on background thread."

parents 7a923666 e1b01e3d
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -9571,6 +9571,8 @@
    <!-- [CHAR_LIMIT=NONE] Developer Settings: Label for the option that turns off all overlays in a given category. -->
    <string name="overlay_option_device_default">Device default</string>
    <!-- [CHAR_LIMIT=NONE] Developer Settings: Toast displayed to the user when an overlay fails to apply. -->
    <string name="overlay_toast_failed_to_apply">Failed to apply overlay</string>
    <!-- [CHAR_LIMIT=60] Label for special access screen -->
    <string name="special_access">Special app access</string>
+36 −17
Original line number Diff line number Diff line
@@ -22,9 +22,12 @@ import android.content.Context;
import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.VisibleForTesting;
import androidx.preference.ListPreference;
@@ -38,6 +41,7 @@ import com.android.settingslib.development.DeveloperOptionsPreferenceController;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

/**
 * Preference controller to allow users to choose an overlay from a list for a given category.
@@ -46,6 +50,7 @@ import java.util.List;
 */
public class OverlayCategoryPreferenceController extends DeveloperOptionsPreferenceController
        implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
    private static final String TAG = "OverlayCategoryPC";
    @VisibleForTesting
    static final String PACKAGE_DEVICE_DEFAULT = "package_device_default";
    private static final String OVERLAY_TARGET_PACKAGE = "android";
@@ -100,12 +105,11 @@ public class OverlayCategoryPreferenceController extends DeveloperOptionsPrefere
    }

    private boolean setOverlay(String packageName) {
        String currentPackageName = null;
        for (OverlayInfo o : getOverlayInfos()) {
            if (o.isEnabled()) {
                currentPackageName = o.packageName;
            }
        }
        final String currentPackageName = getOverlayInfos().stream()
                .filter(info -> info.isEnabled())
                .map(info -> info.packageName)
                .findFirst()
                .orElse(null);

        if (PACKAGE_DEVICE_DEFAULT.equals(packageName) && TextUtils.isEmpty(currentPackageName)
                || TextUtils.equals(packageName, currentPackageName)) {
@@ -113,18 +117,33 @@ public class OverlayCategoryPreferenceController extends DeveloperOptionsPrefere
            return true;
        }

        final boolean result;
        new AsyncTask<Void, Void, Boolean>() {
            @Override
            protected Boolean doInBackground(Void... params) {
                try {
                    if (PACKAGE_DEVICE_DEFAULT.equals(packageName)) {
                result = mOverlayManager.setEnabled(currentPackageName, false, USER_SYSTEM);
                        return mOverlayManager.setEnabled(currentPackageName, false, USER_SYSTEM);
                    } else {
                result = mOverlayManager.setEnabledExclusiveInCategory(packageName, USER_SYSTEM);
                        return mOverlayManager.setEnabledExclusiveInCategory(packageName, USER_SYSTEM);
                    }
                } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
                    Log.w(TAG, "Error enabling overlay.", re);
                    return false;
                }
            }

            @Override
            protected void onPostExecute(Boolean success) {
                updateState(mPreference);
        return result;
                if (!success) {
                    Toast.makeText(
                            mContext, R.string.overlay_toast_failed_to_apply, Toast.LENGTH_LONG)
                            .show();
                }
            }
        }.execute();

        return true; // Assume success; toast on failure.
    }

    @Override
+47 −0
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@ import android.content.om.OverlayInfo;
import android.content.pm.PackageManager;
import android.os.RemoteException;

import com.android.settings.R;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -38,6 +40,8 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.shadows.ShadowToast;

import java.util.ArrayList;
import java.util.Arrays;
@@ -105,21 +109,64 @@ public class OverlayCategoryPreferenceControllerTest {
        mockCurrentOverlays(ONE_DISABLED, TWO_DISABLED);

        mController.onPreferenceChange(null, TWO_DISABLED.packageName);
        ShadowApplication.runBackgroundTasks();

        verify(mOverlayManager)
            .setEnabledExclusiveInCategory(eq(TWO_DISABLED.packageName), anyInt());
    }

    @Test
    public void onPreferenceChange_enable_fails() throws Exception {
        mockCurrentOverlays(ONE_DISABLED, TWO_DISABLED);
        when(mOverlayManager.setEnabledExclusiveInCategory(eq(TWO_DISABLED.packageName), anyInt()))
                .thenReturn(false);

        mController.onPreferenceChange(null, TWO_DISABLED.packageName);
        ShadowApplication.runBackgroundTasks();

        assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
                RuntimeEnvironment.application.getString(R.string.overlay_toast_failed_to_apply));
    }

    @Test
    public void onPreferenceChange_disable() throws Exception {
        mockCurrentOverlays(ONE_DISABLED, TWO_ENABLED);

        mController.onPreferenceChange(
                null, OverlayCategoryPreferenceController.PACKAGE_DEVICE_DEFAULT);
        ShadowApplication.runBackgroundTasks();

        verify(mOverlayManager).setEnabled(eq(TWO_ENABLED.packageName), eq(false), anyInt());
    }

    @Test
    public void onPreferenceChange_disable_fails() throws Exception {
        mockCurrentOverlays(ONE_DISABLED, TWO_ENABLED);
        when(mOverlayManager.setEnabled(eq(TWO_ENABLED.packageName), eq(false), anyInt()))
                .thenReturn(false);

        mController.onPreferenceChange(
                null, OverlayCategoryPreferenceController.PACKAGE_DEVICE_DEFAULT);
        ShadowApplication.runBackgroundTasks();

        assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
                RuntimeEnvironment.application.getString(R.string.overlay_toast_failed_to_apply));
    }

    @Test
    public void onPreferenceChange_disable_throws() throws Exception {
        mockCurrentOverlays(ONE_DISABLED, TWO_ENABLED);
        when(mOverlayManager.setEnabled(eq(TWO_ENABLED.packageName), eq(false), anyInt()))
                .thenThrow(new RemoteException());

        mController.onPreferenceChange(
                null, OverlayCategoryPreferenceController.PACKAGE_DEVICE_DEFAULT);
        ShadowApplication.runBackgroundTasks();

        assertThat(ShadowToast.getTextOfLatestToast()).isEqualTo(
                RuntimeEnvironment.application.getString(R.string.overlay_toast_failed_to_apply));
    }

    @Test
    public void updateState_enabled() {
        mockCurrentOverlays(ONE_DISABLED, TWO_ENABLED);