Enable overlays on background thread.

Change-Id: I445022c2f05788f89a7dd412f70229b4874ebda3
Fixes: 112741125
Test: m RunSettingsRoboTests
This commit is contained in:
Amin Shaikh
2019-01-28 15:31:53 -05:00
parent e56df8877a
commit e1b01e3dd8
3 changed files with 85 additions and 17 deletions

View File

@@ -9557,6 +9557,8 @@
<!-- [CHAR_LIMIT=NONE] Developer Settings: Label for the option that turns off all overlays in a given category. --> <!-- [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> <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 --> <!-- [CHAR_LIMIT=60] Label for special access screen -->
<string name="special_access">Special app access</string> <string name="special_access">Special app access</string>

View File

@@ -22,9 +22,12 @@ import android.content.Context;
import android.content.om.IOverlayManager; import android.content.om.IOverlayManager;
import android.content.om.OverlayInfo; import android.content.om.OverlayInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import androidx.preference.ListPreference; import androidx.preference.ListPreference;
@@ -38,6 +41,7 @@ import com.android.settingslib.development.DeveloperOptionsPreferenceController;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Optional;
/** /**
* Preference controller to allow users to choose an overlay from a list for a given category. * 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 public class OverlayCategoryPreferenceController extends DeveloperOptionsPreferenceController
implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin { implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
private static final String TAG = "OverlayCategoryPC";
@VisibleForTesting @VisibleForTesting
static final String PACKAGE_DEVICE_DEFAULT = "package_device_default"; static final String PACKAGE_DEVICE_DEFAULT = "package_device_default";
private static final String OVERLAY_TARGET_PACKAGE = "android"; private static final String OVERLAY_TARGET_PACKAGE = "android";
@@ -100,12 +105,11 @@ public class OverlayCategoryPreferenceController extends DeveloperOptionsPrefere
} }
private boolean setOverlay(String packageName) { private boolean setOverlay(String packageName) {
String currentPackageName = null; final String currentPackageName = getOverlayInfos().stream()
for (OverlayInfo o : getOverlayInfos()) { .filter(info -> info.isEnabled())
if (o.isEnabled()) { .map(info -> info.packageName)
currentPackageName = o.packageName; .findFirst()
} .orElse(null);
}
if (PACKAGE_DEVICE_DEFAULT.equals(packageName) && TextUtils.isEmpty(currentPackageName) if (PACKAGE_DEVICE_DEFAULT.equals(packageName) && TextUtils.isEmpty(currentPackageName)
|| TextUtils.equals(packageName, currentPackageName)) { || TextUtils.equals(packageName, currentPackageName)) {
@@ -113,18 +117,33 @@ public class OverlayCategoryPreferenceController extends DeveloperOptionsPrefere
return true; return true;
} }
final boolean result; new AsyncTask<Void, Void, Boolean>() {
try { @Override
if (PACKAGE_DEVICE_DEFAULT.equals(packageName)) { protected Boolean doInBackground(Void... params) {
result = mOverlayManager.setEnabled(currentPackageName, false, USER_SYSTEM); try {
} else { if (PACKAGE_DEVICE_DEFAULT.equals(packageName)) {
result = mOverlayManager.setEnabledExclusiveInCategory(packageName, USER_SYSTEM); return mOverlayManager.setEnabled(currentPackageName, false, USER_SYSTEM);
} else {
return mOverlayManager.setEnabledExclusiveInCategory(packageName, USER_SYSTEM);
}
} catch (RemoteException re) {
Log.w(TAG, "Error enabling overlay.", re);
return false;
}
} }
} catch (RemoteException re) {
throw re.rethrowFromSystemServer(); @Override
} protected void onPostExecute(Boolean success) {
updateState(mPreference); 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 @Override

View File

@@ -31,6 +31,8 @@ import android.content.om.OverlayInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.RemoteException; import android.os.RemoteException;
import com.android.settings.R;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@@ -38,6 +40,8 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.shadows.ShadowToast;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -105,21 +109,64 @@ public class OverlayCategoryPreferenceControllerTest {
mockCurrentOverlays(ONE_DISABLED, TWO_DISABLED); mockCurrentOverlays(ONE_DISABLED, TWO_DISABLED);
mController.onPreferenceChange(null, TWO_DISABLED.packageName); mController.onPreferenceChange(null, TWO_DISABLED.packageName);
ShadowApplication.runBackgroundTasks();
verify(mOverlayManager) verify(mOverlayManager)
.setEnabledExclusiveInCategory(eq(TWO_DISABLED.packageName), anyInt()); .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 @Test
public void onPreferenceChange_disable() throws Exception { public void onPreferenceChange_disable() throws Exception {
mockCurrentOverlays(ONE_DISABLED, TWO_ENABLED); mockCurrentOverlays(ONE_DISABLED, TWO_ENABLED);
mController.onPreferenceChange( mController.onPreferenceChange(
null, OverlayCategoryPreferenceController.PACKAGE_DEVICE_DEFAULT); null, OverlayCategoryPreferenceController.PACKAGE_DEVICE_DEFAULT);
ShadowApplication.runBackgroundTasks();
verify(mOverlayManager).setEnabled(eq(TWO_ENABLED.packageName), eq(false), anyInt()); 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 @Test
public void updateState_enabled() { public void updateState_enabled() {
mockCurrentOverlays(ONE_DISABLED, TWO_ENABLED); mockCurrentOverlays(ONE_DISABLED, TWO_ENABLED);