Merge "Fix refresh of "apps that can interrupt" segment" into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
e7c670ea27
@@ -49,7 +49,9 @@ public class CircularIconsPreference extends RestrictedPreference {
|
|||||||
|
|
||||||
private static final float DISABLED_ITEM_ALPHA = 0.3f;
|
private static final float DISABLED_ITEM_ALPHA = 0.3f;
|
||||||
|
|
||||||
record LoadedIcons(ImmutableList<Drawable> icons, int extraItems) { }
|
record LoadedIcons(ImmutableList<Drawable> icons, int extraItems) {
|
||||||
|
static final LoadedIcons EMPTY = new LoadedIcons(ImmutableList.of(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
private Executor mUiExecutor;
|
private Executor mUiExecutor;
|
||||||
|
|
||||||
@@ -126,6 +128,7 @@ public class CircularIconsPreference extends RestrictedPreference {
|
|||||||
// We know what icons we want, but haven't yet loaded them.
|
// We know what icons we want, but haven't yet loaded them.
|
||||||
if (mIconSet.size() == 0) {
|
if (mIconSet.size() == 0) {
|
||||||
container.setVisibility(View.GONE);
|
container.setVisibility(View.GONE);
|
||||||
|
mLoadedIcons = LoadedIcons.EMPTY;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
container.setVisibility(View.VISIBLE);
|
container.setVisibility(View.VISIBLE);
|
||||||
@@ -137,7 +140,7 @@ public class CircularIconsPreference extends RestrictedPreference {
|
|||||||
@Override
|
@Override
|
||||||
public void onGlobalLayout() {
|
public void onGlobalLayout() {
|
||||||
container.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
container.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||||
startLoadingIcons(container, mIconSet);
|
notifyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import static android.provider.Settings.EXTRA_AUTOMATIC_ZEN_RULE_ID;
|
|||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
@@ -49,6 +51,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preference with a link and summary about what apps can break through the mode
|
* Preference with a link and summary about what apps can break through the mode
|
||||||
@@ -65,24 +68,26 @@ class ZenModeAppsLinkPreferenceController extends AbstractZenModePreferenceContr
|
|||||||
private ZenMode mZenMode;
|
private ZenMode mZenMode;
|
||||||
private CircularIconsPreference mPreference;
|
private CircularIconsPreference mPreference;
|
||||||
private final Fragment mHost;
|
private final Fragment mHost;
|
||||||
|
private final Function<ApplicationInfo, Drawable> mAppIconRetriever;
|
||||||
|
|
||||||
ZenModeAppsLinkPreferenceController(Context context, String key, Fragment host,
|
ZenModeAppsLinkPreferenceController(Context context, String key, Fragment host,
|
||||||
ZenModesBackend backend, ZenHelperBackend helperBackend) {
|
ZenModesBackend backend, ZenHelperBackend helperBackend) {
|
||||||
this(context, key, host,
|
this(context, key, host,
|
||||||
ApplicationsState.getInstance((Application) context.getApplicationContext()),
|
ApplicationsState.getInstance((Application) context.getApplicationContext()),
|
||||||
backend, helperBackend);
|
backend, helperBackend, appInfo -> Utils.getBadgedIcon(context, appInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
ZenModeAppsLinkPreferenceController(Context context, String key, Fragment host,
|
ZenModeAppsLinkPreferenceController(Context context, String key, Fragment host,
|
||||||
ApplicationsState applicationsState, ZenModesBackend backend,
|
ApplicationsState applicationsState, ZenModesBackend backend,
|
||||||
ZenHelperBackend helperBackend) {
|
ZenHelperBackend helperBackend, Function<ApplicationInfo, Drawable> appIconRetriever) {
|
||||||
super(context, key, backend);
|
super(context, key, backend);
|
||||||
mSummaryHelper = new ZenModeSummaryHelper(mContext, helperBackend);
|
mSummaryHelper = new ZenModeSummaryHelper(mContext, helperBackend);
|
||||||
mHelperBackend = helperBackend;
|
mHelperBackend = helperBackend;
|
||||||
mApplicationsState = applicationsState;
|
mApplicationsState = applicationsState;
|
||||||
mUserManager = context.getSystemService(UserManager.class);
|
mUserManager = context.getSystemService(UserManager.class);
|
||||||
mHost = host;
|
mHost = host;
|
||||||
|
mAppIconRetriever = appIconRetriever;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -105,13 +110,18 @@ class ZenModeAppsLinkPreferenceController extends AbstractZenModePreferenceContr
|
|||||||
if (zenMode.getPolicy().getAllowedChannels() == ZenPolicy.CHANNEL_POLICY_NONE) {
|
if (zenMode.getPolicy().getAllowedChannels() == ZenPolicy.CHANNEL_POLICY_NONE) {
|
||||||
mPreference.setSummary(R.string.zen_mode_apps_none_apps);
|
mPreference.setSummary(R.string.zen_mode_apps_none_apps);
|
||||||
mPreference.displayIcons(CircularIconSet.EMPTY);
|
mPreference.displayIcons(CircularIconSet.EMPTY);
|
||||||
|
if (mAppSession != null) {
|
||||||
|
mAppSession.deactivateSession();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (TextUtils.isEmpty(mPreference.getSummary())) {
|
if (TextUtils.isEmpty(mPreference.getSummary())) {
|
||||||
mPreference.setSummary(R.string.zen_mode_apps_calculating);
|
mPreference.setSummary(R.string.zen_mode_apps_calculating);
|
||||||
}
|
}
|
||||||
if (mApplicationsState != null && mHost != null) {
|
if (mAppSession == null) {
|
||||||
mAppSession = mApplicationsState.newSession(mAppSessionCallbacks,
|
mAppSession = mApplicationsState.newSession(mAppSessionCallbacks,
|
||||||
mHost.getLifecycle());
|
mHost.getLifecycle());
|
||||||
|
} else {
|
||||||
|
mAppSession.activateSession();
|
||||||
}
|
}
|
||||||
triggerUpdateAppsBypassingDnd();
|
triggerUpdateAppsBypassingDnd();
|
||||||
}
|
}
|
||||||
@@ -133,12 +143,16 @@ class ZenModeAppsLinkPreferenceController extends AbstractZenModePreferenceContr
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void displayAppsBypassingDnd(List<AppEntry> allApps) {
|
private void displayAppsBypassingDnd(List<AppEntry> allApps) {
|
||||||
|
if (mZenMode.getPolicy().getAllowedChannels() == ZenPolicy.CHANNEL_POLICY_NONE) {
|
||||||
|
// Can get this callback when resuming, if we had CHANNEL_POLICY_PRIORITY and just
|
||||||
|
// switched to CHANNEL_POLICY_NONE.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ImmutableList<AppEntry> apps = getAppsBypassingDndSortedByName(allApps);
|
ImmutableList<AppEntry> apps = getAppsBypassingDndSortedByName(allApps);
|
||||||
|
|
||||||
mPreference.setSummary(mSummaryHelper.getAppsSummary(mZenMode, apps));
|
mPreference.setSummary(mSummaryHelper.getAppsSummary(mZenMode, apps));
|
||||||
|
|
||||||
mPreference.displayIcons(new CircularIconSet<>(apps,
|
mPreference.displayIcons(new CircularIconSet<>(apps,
|
||||||
app -> Utils.getBadgedIcon(mContext, app.info)),
|
app -> mAppIconRetriever.apply(app.info)),
|
||||||
APP_ENTRY_EQUIVALENCE);
|
APP_ENTRY_EQUIVALENCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
@@ -103,11 +104,12 @@ public final class ZenModeAppsLinkPreferenceControllerTest {
|
|||||||
mContext = RuntimeEnvironment.application;
|
mContext = RuntimeEnvironment.application;
|
||||||
CircularIconSet.sExecutorService = MoreExecutors.newDirectExecutorService();
|
CircularIconSet.sExecutorService = MoreExecutors.newDirectExecutorService();
|
||||||
mPreference = new TestableCircularIconsPreference(mContext);
|
mPreference = new TestableCircularIconsPreference(mContext);
|
||||||
|
|
||||||
when(mApplicationsState.newSession(any(), any())).thenReturn(mSession);
|
when(mApplicationsState.newSession(any(), any())).thenReturn(mSession);
|
||||||
|
|
||||||
mController = new ZenModeAppsLinkPreferenceController(
|
mController = new ZenModeAppsLinkPreferenceController(
|
||||||
mContext, "controller_key", mock(Fragment.class), mApplicationsState,
|
mContext, "controller_key", mock(Fragment.class), mApplicationsState,
|
||||||
mZenModesBackend, mHelperBackend);
|
mZenModesBackend, mHelperBackend,
|
||||||
|
/* appIconRetriever= */ appInfo -> new ColorDrawable());
|
||||||
|
|
||||||
// Ensure the preference view is bound & measured (needed to add child ImageViews).
|
// Ensure the preference view is bound & measured (needed to add child ImageViews).
|
||||||
View preferenceView = LayoutInflater.from(mContext).inflate(mPreference.getLayoutResource(),
|
View preferenceView = LayoutInflater.from(mContext).inflate(mPreference.getLayoutResource(),
|
||||||
@@ -296,6 +298,89 @@ public final class ZenModeAppsLinkPreferenceControllerTest {
|
|||||||
verify(mSession, times(2)).rebuild(any(), any(), eq(false));
|
verify(mSession, times(2)).rebuild(any(), any(), eq(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateState_noneToPriority_loadsBypassingAppsAndListensForChanges() {
|
||||||
|
ZenMode zenModeWithNone = new TestModeBuilder()
|
||||||
|
.setZenPolicy(new ZenPolicy.Builder().allowPriorityChannels(false).build())
|
||||||
|
.build();
|
||||||
|
ZenMode zenModeWithPriority = new TestModeBuilder()
|
||||||
|
.setZenPolicy(new ZenPolicy.Builder().allowPriorityChannels(true).build())
|
||||||
|
.build();
|
||||||
|
ArrayList<ApplicationsState.AppEntry> appEntries = new ArrayList<>();
|
||||||
|
appEntries.add(createAppEntry("test", mContext.getUserId()));
|
||||||
|
when(mHelperBackend.getPackagesBypassingDnd(mContext.getUserId(), false))
|
||||||
|
.thenReturn(List.of("test"));
|
||||||
|
|
||||||
|
mController.updateState(mPreference, zenModeWithNone);
|
||||||
|
|
||||||
|
assertThat(mPreference.getLoadedIcons().icons()).hasSize(0);
|
||||||
|
verifyNoMoreInteractions(mApplicationsState);
|
||||||
|
verifyNoMoreInteractions(mSession);
|
||||||
|
|
||||||
|
mController.updateState(mPreference, zenModeWithPriority);
|
||||||
|
|
||||||
|
verify(mApplicationsState).newSession(any(), any());
|
||||||
|
verify(mSession).rebuild(any(), any(), anyBoolean());
|
||||||
|
mController.mAppSessionCallbacks.onRebuildComplete(appEntries);
|
||||||
|
assertThat(mPreference.getLoadedIcons().icons()).hasSize(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateState_priorityToNone_clearsBypassingAppsAndStopsListening() {
|
||||||
|
ZenMode zenModeWithNone = new TestModeBuilder()
|
||||||
|
.setZenPolicy(new ZenPolicy.Builder().allowPriorityChannels(false).build())
|
||||||
|
.build();
|
||||||
|
ZenMode zenModeWithPriority = new TestModeBuilder()
|
||||||
|
.setZenPolicy(new ZenPolicy.Builder().allowPriorityChannels(true).build())
|
||||||
|
.build();
|
||||||
|
ArrayList<ApplicationsState.AppEntry> appEntries = new ArrayList<>();
|
||||||
|
appEntries.add(createAppEntry("test", mContext.getUserId()));
|
||||||
|
when(mHelperBackend.getPackagesBypassingDnd(mContext.getUserId(), false))
|
||||||
|
.thenReturn(List.of("test"));
|
||||||
|
|
||||||
|
mController.updateState(mPreference, zenModeWithPriority);
|
||||||
|
|
||||||
|
verify(mApplicationsState).newSession(any(), any());
|
||||||
|
verify(mSession).rebuild(any(), any(), anyBoolean());
|
||||||
|
mController.mAppSessionCallbacks.onRebuildComplete(appEntries);
|
||||||
|
assertThat(mPreference.getLoadedIcons().icons()).hasSize(1);
|
||||||
|
|
||||||
|
mController.updateState(mPreference, zenModeWithNone);
|
||||||
|
|
||||||
|
assertThat(mPreference.getLoadedIcons().icons()).hasSize(0);
|
||||||
|
verify(mSession).deactivateSession();
|
||||||
|
verifyNoMoreInteractions(mSession);
|
||||||
|
verifyNoMoreInteractions(mApplicationsState);
|
||||||
|
|
||||||
|
// An errant callback (triggered by onResume and received asynchronously after
|
||||||
|
// updateState()) is ignored.
|
||||||
|
mController.mAppSessionCallbacks.onRebuildComplete(appEntries);
|
||||||
|
|
||||||
|
assertThat(mPreference.getLoadedIcons().icons()).hasSize(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateState_priorityToNoneToPriority_restartsListening() {
|
||||||
|
ZenMode zenModeWithNone = new TestModeBuilder()
|
||||||
|
.setZenPolicy(new ZenPolicy.Builder().allowPriorityChannels(false).build())
|
||||||
|
.build();
|
||||||
|
ZenMode zenModeWithPriority = new TestModeBuilder()
|
||||||
|
.setZenPolicy(new ZenPolicy.Builder().allowPriorityChannels(true).build())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
mController.updateState(mPreference, zenModeWithPriority);
|
||||||
|
verify(mApplicationsState).newSession(any(), any());
|
||||||
|
verify(mSession).rebuild(any(), any(), anyBoolean());
|
||||||
|
|
||||||
|
mController.updateState(mPreference, zenModeWithNone);
|
||||||
|
verifyNoMoreInteractions(mApplicationsState);
|
||||||
|
verify(mSession).deactivateSession();
|
||||||
|
|
||||||
|
mController.updateState(mPreference, zenModeWithPriority);
|
||||||
|
verifyNoMoreInteractions(mApplicationsState);
|
||||||
|
verify(mSession).activateSession();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoCrashIfAppsReadyBeforeRuleAvailable() {
|
public void testNoCrashIfAppsReadyBeforeRuleAvailable() {
|
||||||
mController.mAppSessionCallbacks.onLoadEntriesCompleted();
|
mController.mAppSessionCallbacks.onLoadEntriesCompleted();
|
||||||
|
|||||||
Reference in New Issue
Block a user