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

Commit e1b01e3d authored by Amin Shaikh's avatar Amin Shaikh
Browse files

Enable overlays on background thread.

Change-Id: I445022c2f05788f89a7dd412f70229b4874ebda3
Fixes: 112741125
Test: m RunSettingsRoboTests
parent e56df887
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -9557,6 +9557,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);