Merge changes from topic "b168904199-qs-injection"

* changes:
  2/N Remove last injection from QSCustomizer
  1/N Add QSCustomizerController
This commit is contained in:
Dave Mankoff
2020-11-04 14:09:39 +00:00
committed by Android (Google) Code Review
17 changed files with 410 additions and 273 deletions

View File

@@ -57,7 +57,7 @@ public class QSDetail extends LinearLayout {
protected TextView mDetailDoneButton;
private QSDetailClipper mClipper;
private DetailAdapter mDetailAdapter;
private QSPanel mQsPanel;
private QSPanelController mQsPanelController;
protected View mQsDetailHeader;
protected TextView mQsDetailHeaderTitle;
@@ -114,19 +114,20 @@ public class QSDetail extends LinearLayout {
public void onClick(View v) {
announceForAccessibility(
mContext.getString(R.string.accessibility_desc_quick_settings));
mQsPanel.closeDetail();
mQsPanelController.closeDetail();
}
};
mDetailDoneButton.setOnClickListener(doneListener);
}
/** */
public void setQsPanel(QSPanel panel, QuickStatusBarHeader header, QSFooter footer) {
mQsPanel = panel;
public void setQsPanel(QSPanelController panelController, QuickStatusBarHeader header,
QSFooter footer) {
mQsPanelController = panelController;
mHeader = header;
mFooter = footer;
mHeader.setCallback(mQsPanelCallback);
mQsPanel.setCallback(mQsPanelCallback);
mQsPanelController.setCallback(mQsPanelCallback);
}
public void setHost(QSTileHost host) {
@@ -221,7 +222,7 @@ public class QSDetail extends LinearLayout {
listener = mTeardownDetailWhenDone;
mHeader.setVisibility(View.VISIBLE);
mFooter.setVisibility(View.VISIBLE);
mQsPanel.setGridContentVisibility(true);
mQsPanelController.setGridContentVisibility(true);
mQsPanelCallback.onScanStateChanged(false);
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
@@ -362,7 +363,7 @@ public class QSDetail extends LinearLayout {
public void onAnimationEnd(Animator animation) {
// Only hide content if still in detail state.
if (mDetailAdapter != null) {
mQsPanel.setGridContentVisibility(false);
mQsPanelController.setGridContentVisibility(false);
mHeader.setVisibility(View.INVISIBLE);
mFooter.setVisibility(View.INVISIBLE);
}

View File

@@ -38,7 +38,7 @@ import com.android.systemui.R;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSFragmentComponent;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.StatusBarState;
@@ -69,7 +69,6 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
private QSAnimator mQSAnimator;
private HeightListener mPanelView;
protected QuickStatusBarHeader mHeader;
private QSCustomizer mQSCustomizer;
protected NonInterceptingScrollView mQSPanelScrollView;
private QSDetail mQSDetail;
private boolean mListening;
@@ -97,6 +96,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
private float mLastHeaderTranslation;
private QSPanelController mQSPanelController;
private QuickQSPanelController mQuickQSPanelController;
private QSCustomizerController mQSCustomizerController;
@Inject
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
@@ -148,16 +148,17 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
mQSContainerImplController.init();
mContainer = mQSContainerImplController.getView();
mQSDetail.setQsPanel(mQSPanelController.getView(), mHeader, mFooter);
mQSDetail.setQsPanel(mQSPanelController, mHeader, mFooter);
mQSAnimator = qsFragmentComponent.getQSAnimator();
mQSCustomizer = view.findViewById(R.id.qs_customize);
mQSCustomizer.setQs(this);
mQSCustomizerController = qsFragmentComponent.getQSCustomizerController();
mQSCustomizerController.init();
mQSCustomizerController.setQs(this);
if (savedInstanceState != null) {
setExpanded(savedInstanceState.getBoolean(EXTRA_EXPANDED));
setListening(savedInstanceState.getBoolean(EXTRA_LISTENING));
setEditLocation(view);
mQSCustomizer.restoreInstanceState(savedInstanceState);
mQSCustomizerController.restoreInstanceState(savedInstanceState);
if (mQsExpanded) {
mQSPanelController.getTileLayout().restoreInstanceState(savedInstanceState);
}
@@ -181,7 +182,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
if (mListening) {
setListening(false);
}
mQSCustomizer.setQs(null);
mQSCustomizerController.setQs(null);
}
@Override
@@ -189,7 +190,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
super.onSaveInstanceState(outState);
outState.putBoolean(EXTRA_EXPANDED, mQsExpanded);
outState.putBoolean(EXTRA_LISTENING, mListening);
mQSCustomizer.saveInstanceState(outState);
mQSCustomizerController.saveInstanceState(outState);
if (mQsExpanded) {
mQSPanelController.getTileLayout().saveInstanceState(outState);
}
@@ -236,23 +237,22 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
int[] loc = edit.getLocationOnScreen();
int x = loc[0] + edit.getWidth() / 2;
int y = loc[1] + edit.getHeight() / 2;
mQSCustomizer.setEditLocation(x, y);
mQSCustomizerController.setEditLocation(x, y);
}
@Override
public void setContainer(ViewGroup container) {
if (container instanceof NotificationsQuickSettingsContainer) {
mQSCustomizer.setContainer((NotificationsQuickSettingsContainer) container);
mQSCustomizerController.setContainer((NotificationsQuickSettingsContainer) container);
}
}
@Override
public boolean isCustomizing() {
return mQSCustomizer.isCustomizing();
return mQSCustomizerController.isCustomizing();
}
public void setHost(QSTileHost qsh) {
mQSPanelController.setCustomizer(mQSCustomizer);
mHeader.setQSPanel(mQSPanelController.getView());
mFooter.setQSPanel(mQSPanelController.getView());
mQSDetail.setHost(qsh);
@@ -325,10 +325,6 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
return mQSPanelController.getView();
}
public QSCustomizer getCustomizer() {
return mQSCustomizer;
}
@Override
public boolean isShowingDetail() {
return mQSPanelController.isShowingCustomize() || mQSDetail.isShowingDetail();
@@ -553,9 +549,10 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
public void notifyCustomizeChanged() {
// The customize state changed, so our height changed.
mContainer.updateExpansion();
mQSPanelScrollView.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE
mQSPanelScrollView.setVisibility(!mQSCustomizerController.isCustomizing() ? View.VISIBLE
: View.INVISIBLE);
mFooter.setVisibility(!mQSCustomizer.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
mFooter.setVisibility(
!mQSCustomizerController.isCustomizing() ? View.VISIBLE : View.INVISIBLE);
// Let the panel know the position changed and it needs to update where notifications
// and whatnot are.
mPanelView.onQsHeightChanged();
@@ -567,7 +564,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
*/
@Override
public int getDesiredHeight() {
if (mQSCustomizer.isCustomizing()) {
if (mQSCustomizerController.isCustomizing()) {
return getView().getHeight();
}
if (mQSDetail.isClosingDetail()) {

View File

@@ -608,12 +608,6 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi
}
}
public void onCollapse() {
if (mCustomizePanel != null && mCustomizePanel.isShown()) {
mCustomizePanel.hide();
}
}
public void setExpanded(boolean expanded) {
if (mExpanded == expanded) return;
mQSLogger.logPanelExpanded(expanded, getDumpableTag());
@@ -742,29 +736,7 @@ public class QSPanel extends LinearLayout implements Tunable, BrightnessMirrorLi
mTileLayout.removeTile(tileRecord);
}
public void showEdit(final View v) {
v.post(new Runnable() {
@Override
public void run() {
if (mCustomizePanel != null) {
if (!mCustomizePanel.isCustomizing()) {
int[] loc = v.getLocationOnScreen();
int x = loc[0] + v.getWidth() / 2;
int y = loc[1] + v.getHeight() / 2;
mCustomizePanel.show(x, y);
}
}
}
});
}
public void closeDetail() {
if (mCustomizePanel != null && mCustomizePanel.isShown()) {
// Treat this as a detail panel for now, to make things easy.
mCustomizePanel.hide();
return;
}
void closeDetail() {
showDetail(false, mDetailRecord);
}

View File

@@ -29,7 +29,7 @@ import com.android.systemui.R;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.settings.BrightnessController;
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
@@ -44,6 +44,7 @@ import javax.inject.Inject;
public class QSPanelController extends QSPanelControllerBase<QSPanel> {
private final QSSecurityFooter mQsSecurityFooter;
private final TunerService mTunerService;
private final QSCustomizerController mQsCustomizerController;
private final BrightnessController mBrightnessController;
private final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
@@ -61,15 +62,23 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
@Inject
QSPanelController(QSPanel view, QSSecurityFooter qsSecurityFooter, TunerService tunerService,
QSTileHost qstileHost, DumpManager dumpManager,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
QSTileHost qstileHost, QSCustomizerController qsCustomizerController,
DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
BrightnessController.Factory brightnessControllerFactory) {
super(view, qstileHost, metricsLogger, uiEventLogger, dumpManager);
super(view, qstileHost, qsCustomizerController, metricsLogger, uiEventLogger, dumpManager);
mQsSecurityFooter = qsSecurityFooter;
mTunerService = tunerService;
mQsCustomizerController = qsCustomizerController;
mQsSecurityFooter.setHostEnvironment(qstileHost);
mBrightnessController = brightnessControllerFactory.create(
mView.findViewById(R.id.brightness_slider));
mView.setCustomizer(mQsCustomizerController.getView());
}
@Override
public void onInit() {
mQsCustomizerController.init();
}
@Override
@@ -114,11 +123,6 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
return mView.getTileLayout();
}
/** */
public void setCustomizer(QSCustomizer customizer) {
mView.setCustomizer(customizer);
}
/** */
public boolean isShowingCustomize() {
return mView.isShowingCustomize();
@@ -196,6 +200,23 @@ public class QSPanelController extends QSPanelControllerBase<QSPanel> {
/** Start customizing the Quick Settings. */
public void showEdit(View view) {
mView.showEdit(view);
view.post(() -> {
if (!mQsCustomizerController.isCustomizing()) {
int[] loc = view.getLocationOnScreen();
int x = loc[0] + view.getWidth() / 2;
int y = loc[1] + view.getHeight() / 2;
mQsCustomizerController.show(x, y, false);
}
});
}
/** */
public void setCallback(QSDetail.Callback qsPanelCallback) {
mView.setCallback(qsPanelCallback);
}
/** */
public void setGridContentVisibility(boolean visible) {
mView.setGridContentVisibility(visible);
}
}

View File

@@ -29,6 +29,7 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTileView;
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.util.ViewController;
@@ -46,6 +47,7 @@ import java.util.stream.Collectors;
public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewController<T>
implements Dumpable{
protected final QSTileHost mHost;
private final QSCustomizerController mQsCustomizerController;
private final MediaHost mMediaHost;
private final MetricsLogger mMetricsLogger;
private final UiEventLogger mUiEventLogger;
@@ -69,9 +71,11 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
private String mCachedSpecs = "";
protected QSPanelControllerBase(T view, QSTileHost host,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger, DumpManager dumpManager) {
QSCustomizerController qsCustomizerController, MetricsLogger metricsLogger,
UiEventLogger uiEventLogger, DumpManager dumpManager) {
super(view);
mHost = host;
mQsCustomizerController = qsCustomizerController;
mMediaHost = mView.getMediaHost();
mMetricsLogger = metricsLogger;
mUiEventLogger = uiEventLogger;
@@ -192,6 +196,10 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
/** */
public void closeDetail() {
if (mQsCustomizerController.isShown()) {
mQsCustomizerController.hide();
return;
}
mView.closeDetail();
}

View File

@@ -23,6 +23,7 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -41,9 +42,10 @@ public class QuickQSPanelController extends QSPanelControllerBase<QuickQSPanel>
@Inject
QuickQSPanelController(QuickQSPanel view, TunerService tunerService, QSTileHost qsTileHost,
QSCustomizerController qsCustomizerController,
MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
DumpManager dumpManager) {
super(view, qsTileHost, metricsLogger, uiEventLogger, dumpManager);
super(view, qsTileHost, qsCustomizerController, metricsLogger, uiEventLogger, dumpManager);
mTunerService = tunerService;
}

View File

@@ -20,41 +20,23 @@ import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Toolbar;
import android.widget.Toolbar.OnMenuItemClickListener;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.UiEventLoggerImpl;
import com.android.systemui.R;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSDetailClipper;
import com.android.systemui.qs.QSEditEvent;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.KeyguardStateController.Callback;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
/**
* Allows full-screen customization of QS, through show() and hide().
@@ -62,24 +44,16 @@ import javax.inject.Inject;
* This adds itself to the status bar window, so it can appear on top of quick settings and
* *someday* do fancy animations to get into/out of it.
*/
public class QSCustomizer extends LinearLayout implements OnMenuItemClickListener {
public class QSCustomizer extends LinearLayout {
private static final int MENU_RESET = Menu.FIRST;
private static final String EXTRA_QS_CUSTOMIZING = "qs_customizing";
private static final String TAG = "QSCustomizer";
static final int MENU_RESET = Menu.FIRST;
static final String EXTRA_QS_CUSTOMIZING = "qs_customizing";
private final QSDetailClipper mClipper;
private final LightBarController mLightBarController;
private KeyguardStateController mKeyguardStateController;
private final ScreenLifecycle mScreenLifecycle;
private final TileQueryHelper mTileQueryHelper;
private final View mTransparentView;
private final QSTileHost mHost;
private boolean isShown;
private RecyclerView mRecyclerView;
private TileAdapter mTileAdapter;
private Toolbar mToolbar;
private final RecyclerView mRecyclerView;
private boolean mCustomizing;
private NotificationsQuickSettingsContainer mNotifQsContainer;
private QS mQs;
@@ -87,90 +61,47 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
private int mY;
private boolean mOpening;
private boolean mIsShowingNavBackdrop;
private UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
@Inject
public QSCustomizer(Context context, AttributeSet attrs,
LightBarController lightBarController,
KeyguardStateController keyguardStateController,
ScreenLifecycle screenLifecycle,
TileQueryHelper tileQueryHelper,
QSTileHost qsTileHost,
UiEventLogger uiEventLogger) {
public QSCustomizer(Context context, AttributeSet attrs) {
super(new ContextThemeWrapper(context, R.style.edit_theme), attrs);
LayoutInflater.from(getContext()).inflate(R.layout.qs_customize_panel_content, this);
mClipper = new QSDetailClipper(findViewById(R.id.customize_container));
mToolbar = findViewById(com.android.internal.R.id.action_bar);
Toolbar toolbar = findViewById(com.android.internal.R.id.action_bar);
TypedValue value = new TypedValue();
mContext.getTheme().resolveAttribute(android.R.attr.homeAsUpIndicator, value, true);
mToolbar.setNavigationIcon(
toolbar.setNavigationIcon(
getResources().getDrawable(value.resourceId, mContext.getTheme()));
mToolbar.setNavigationOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
hide();
}
});
mToolbar.setOnMenuItemClickListener(this);
mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
toolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
mContext.getString(com.android.internal.R.string.reset));
mToolbar.setTitle(R.string.qs_edit);
toolbar.setTitle(R.string.qs_edit);
mRecyclerView = findViewById(android.R.id.list);
mTransparentView = findViewById(R.id.customizer_transparent_view);
mTileAdapter = new TileAdapter(getContext(), uiEventLogger);
mTileQueryHelper = tileQueryHelper;
mTileQueryHelper.setListener(mTileAdapter);
mRecyclerView.setAdapter(mTileAdapter);
mTileAdapter.getItemTouchHelper().attachToRecyclerView(mRecyclerView);
GridLayoutManager layout = new GridLayoutManager(getContext(), 3) {
@Override
public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler,
RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) {
// Do not read row and column every time it changes.
}
};
layout.setSpanSizeLookup(mTileAdapter.getSizeLookup());
mRecyclerView.setLayoutManager(layout);
mRecyclerView.addItemDecoration(mTileAdapter.getItemDecoration());
mRecyclerView.addItemDecoration(mTileAdapter.getMarginItemDecoration());
DefaultItemAnimator animator = new DefaultItemAnimator();
animator.setMoveDuration(TileAdapter.MOVE_DURATION);
mRecyclerView.setItemAnimator(animator);
mLightBarController = lightBarController;
mKeyguardStateController = keyguardStateController;
mScreenLifecycle = screenLifecycle;
mHost = qsTileHost;
mTileAdapter.setHost(mHost);
updateNavBackDrop(getResources().getConfiguration());
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
updateNavBackDrop(newConfig);
updateResources();
}
private void updateResources() {
void updateResources() {
LayoutParams lp = (LayoutParams) mTransparentView.getLayoutParams();
lp.height = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.quick_qs_offset_height);
mTransparentView.setLayoutParams(lp);
}
private void updateNavBackDrop(Configuration newConfig) {
void updateNavBackDrop(Configuration newConfig, LightBarController lightBarController) {
View navBackdrop = findViewById(R.id.nav_bar_background);
mIsShowingNavBackdrop = newConfig.smallestScreenWidthDp >= 600
|| newConfig.orientation != Configuration.ORIENTATION_LANDSCAPE;
if (navBackdrop != null) {
navBackdrop.setVisibility(mIsShowingNavBackdrop ? View.VISIBLE : View.GONE);
}
updateNavColors();
updateNavColors(lightBarController);
}
private void updateNavColors() {
mLightBarController.setQsCustomizing(mIsShowingNavBackdrop && isShown);
void updateNavColors(LightBarController lightBarController) {
lightBarController.setQsCustomizing(mIsShowingNavBackdrop && isShown);
}
public void setContainer(NotificationsQuickSettingsContainer notificationsQsContainer) {
@@ -184,39 +115,30 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
/** Animate and show QSCustomizer panel.
* @param x,y Location on screen of {@code edit} button to determine center of animation.
*/
public void show(int x, int y) {
void show(int x, int y, TileAdapter tileAdapter) {
if (!isShown) {
int containerLocation[] = findViewById(R.id.customize_container).getLocationOnScreen();
int[] containerLocation = findViewById(R.id.customize_container).getLocationOnScreen();
mX = x - containerLocation[0];
mY = y - containerLocation[1];
mUiEventLogger.log(QSEditEvent.QS_EDIT_OPEN);
isShown = true;
mOpening = true;
setTileSpecs();
setVisibility(View.VISIBLE);
mClipper.animateCircularClip(mX, mY, true, mExpandAnimationListener);
queryTiles();
mClipper.animateCircularClip(mX, mY, true, new ExpandAnimatorListener(tileAdapter));
mNotifQsContainer.setCustomizerAnimating(true);
mNotifQsContainer.setCustomizerShowing(true);
mKeyguardStateController.addCallback(mKeyguardCallback);
updateNavColors();
}
}
public void showImmediately() {
void showImmediately() {
if (!isShown) {
setVisibility(VISIBLE);
mClipper.cancelAnimator();
mClipper.showBackground();
isShown = true;
setTileSpecs();
setCustomizing(true);
queryTiles();
mNotifQsContainer.setCustomizerAnimating(false);
mNotifQsContainer.setCustomizerShowing(true);
mKeyguardStateController.addCallback(mKeyguardCallback);
updateNavColors();
}
}
@@ -225,9 +147,6 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
* {@link TileAdapter}.
*/
public void setContentPaddings(int paddingStart, int paddingEnd) {
int halfMargin = mContext.getResources()
.getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal) / 2;
mTileAdapter.changeHalfMargin(halfMargin);
mRecyclerView.setPaddingRelative(
paddingStart,
mRecyclerView.getPaddingTop(),
@@ -236,22 +155,14 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
);
}
private void queryTiles() {
mTileQueryHelper.queryTiles(mHost);
}
public void hide() {
final boolean animate = mScreenLifecycle.getScreenState() != ScreenLifecycle.SCREEN_OFF;
/** Hide the customizer. */
public void hide(boolean animate) {
if (isShown) {
mUiEventLogger.log(QSEditEvent.QS_EDIT_CLOSED);
isShown = false;
mToolbar.dismissPopupMenus();
mClipper.cancelAnimator();
// Make sure we're not opening (because we're closing). Nobody can think we are
// customizing after the next two lines.
mOpening = false;
setCustomizing(false);
save();
if (animate) {
mClipper.animateCircularClip(mX, mY, false, mCollapseAnimationListener);
} else {
@@ -259,8 +170,6 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
}
mNotifQsContainer.setCustomizerAnimating(animate);
mNotifQsContainer.setCustomizerShowing(false);
mKeyguardStateController.removeCallback(mKeyguardCallback);
updateNavColors();
}
}
@@ -268,7 +177,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
return isShown;
}
private void setCustomizing(boolean customizing) {
void setCustomizing(boolean customizing) {
mCustomizing = customizing;
mQs.notifyCustomizeChanged();
}
@@ -277,78 +186,21 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
return mCustomizing || mOpening;
}
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case MENU_RESET:
mUiEventLogger.log(QSEditEvent.QS_EDIT_RESET);
reset();
break;
}
return false;
}
private void reset() {
mTileAdapter.resetTileSpecs(mHost, QSTileHost.getDefaultSpecs(mContext));
}
private void setTileSpecs() {
List<String> specs = new ArrayList<>();
for (QSTile tile : mHost.getTiles()) {
specs.add(tile.getTileSpec());
}
mTileAdapter.setTileSpecs(specs);
mRecyclerView.setAdapter(mTileAdapter);
}
private void save() {
if (mTileQueryHelper.isFinished()) {
mTileAdapter.saveSpecs(mHost);
}
}
public void saveInstanceState(Bundle outState) {
if (isShown) {
mKeyguardStateController.removeCallback(mKeyguardCallback);
}
outState.putBoolean(EXTRA_QS_CUSTOMIZING, mCustomizing);
}
public void restoreInstanceState(Bundle savedInstanceState) {
boolean customizing = savedInstanceState.getBoolean(EXTRA_QS_CUSTOMIZING);
if (customizing) {
setVisibility(VISIBLE);
addOnLayoutChangeListener(new OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft,
int oldTop, int oldRight, int oldBottom) {
removeOnLayoutChangeListener(this);
showImmediately();
}
});
}
}
/** @param x,y Location on screen of animation center.
*/
public void setEditLocation(int x, int y) {
int containerLocation[] = findViewById(R.id.customize_container).getLocationOnScreen();
int[] containerLocation = findViewById(R.id.customize_container).getLocationOnScreen();
mX = x - containerLocation[0];
mY = y - containerLocation[1];
}
private final Callback mKeyguardCallback = new Callback() {
@Override
public void onKeyguardShowingChanged() {
if (!isAttachedToWindow()) return;
if (mKeyguardStateController.isShowing() && !mOpening) {
hide();
}
}
};
class ExpandAnimatorListener extends AnimatorListenerAdapter {
private final TileAdapter mTileAdapter;
ExpandAnimatorListener(TileAdapter tileAdapter) {
mTileAdapter = tileAdapter;
}
private final AnimatorListener mExpandAnimationListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (isShown) {
@@ -356,6 +208,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
}
mOpening = false;
mNotifQsContainer.setCustomizerAnimating(false);
mRecyclerView.setAdapter(mTileAdapter);
}
@Override
@@ -363,7 +216,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
mOpening = false;
mNotifQsContainer.setCustomizerAnimating(false);
}
};
}
private final AnimatorListener mCollapseAnimationListener = new AnimatorListenerAdapter() {
@Override
@@ -372,7 +225,6 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
setVisibility(View.GONE);
}
mNotifQsContainer.setCustomizerAnimating(false);
mRecyclerView.setAdapter(mTileAdapter);
}
@Override
@@ -383,4 +235,12 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
mNotifQsContainer.setCustomizerAnimating(false);
}
};
}
public RecyclerView getRecyclerView() {
return mRecyclerView;
}
public boolean isOpening() {
return mOpening;
}
}

View File

@@ -0,0 +1,252 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.qs.customize;
import static com.android.systemui.qs.customize.QSCustomizer.EXTRA_QS_CUSTOMIZING;
import static com.android.systemui.qs.customize.QSCustomizer.MENU_RESET;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toolbar;
import android.widget.Toolbar.OnMenuItemClickListener;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.internal.logging.UiEventLogger;
import com.android.systemui.R;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSEditEvent;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.statusbar.phone.LightBarController;
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.ViewController;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
/** {@link ViewController} for {@link QSCustomizer}. */
@QSScope
public class QSCustomizerController extends ViewController<QSCustomizer> {
private final TileQueryHelper mTileQueryHelper;
private final QSTileHost mQsTileHost;
private final TileAdapter mTileAdapter;
private final ScreenLifecycle mScreenLifecycle;
private final KeyguardStateController mKeyguardStateController;
private final LightBarController mLightBarController;
private final ConfigurationController mConfigurationController;
private final UiEventLogger mUiEventLogger;
private final Toolbar mToolbar;
private final OnMenuItemClickListener mOnMenuItemClickListener = new OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == MENU_RESET) {
mUiEventLogger.log(QSEditEvent.QS_EDIT_RESET);
reset();
}
return false;
}
};
private final KeyguardStateController.Callback mKeyguardCallback =
new KeyguardStateController.Callback() {
@Override
public void onKeyguardShowingChanged() {
if (!mView.isAttachedToWindow()) return;
if (mKeyguardStateController.isShowing() && !mView.isOpening()) {
hide();
}
}
};
private final ConfigurationListener mConfigurationListener = new ConfigurationListener() {
@Override
public void onConfigChanged(Configuration newConfig) {
mView.updateNavBackDrop(newConfig, mLightBarController);
mView.updateResources();
}
};
@Inject
protected QSCustomizerController(QSCustomizer view, TileQueryHelper tileQueryHelper,
QSTileHost qsTileHost, TileAdapter tileAdapter, ScreenLifecycle screenLifecycle,
KeyguardStateController keyguardStateController, LightBarController lightBarController,
ConfigurationController configurationController, UiEventLogger uiEventLogger) {
super(view);
mTileQueryHelper = tileQueryHelper;
mQsTileHost = qsTileHost;
mTileAdapter = tileAdapter;
mScreenLifecycle = screenLifecycle;
mKeyguardStateController = keyguardStateController;
mLightBarController = lightBarController;
mConfigurationController = configurationController;
mUiEventLogger = uiEventLogger;
mToolbar = mView.findViewById(com.android.internal.R.id.action_bar);
}
@Override
protected void onViewAttached() {
mView.updateNavBackDrop(getResources().getConfiguration(), mLightBarController);
mConfigurationController.addCallback(mConfigurationListener);
mTileQueryHelper.setListener(mTileAdapter);
int halfMargin =
getResources().getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal) / 2;
mTileAdapter.changeHalfMargin(halfMargin);
RecyclerView recyclerView = mView.getRecyclerView();
recyclerView.setAdapter(mTileAdapter);
mTileAdapter.getItemTouchHelper().attachToRecyclerView(recyclerView);
GridLayoutManager layout = new GridLayoutManager(getContext(), 3) {
@Override
public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler,
RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) {
// Do not read row and column every time it changes.
}
};
layout.setSpanSizeLookup(mTileAdapter.getSizeLookup());
recyclerView.setLayoutManager(layout);
recyclerView.addItemDecoration(mTileAdapter.getItemDecoration());
recyclerView.addItemDecoration(mTileAdapter.getMarginItemDecoration());
mToolbar.setOnMenuItemClickListener(mOnMenuItemClickListener);
mToolbar.setNavigationOnClickListener(v -> hide());
}
@Override
protected void onViewDetached() {
mTileQueryHelper.setListener(null);
mToolbar.setOnMenuItemClickListener(null);
mConfigurationController.removeCallback(mConfigurationListener);
}
private void reset() {
mTileAdapter.resetTileSpecs(QSTileHost.getDefaultSpecs(getContext()));
}
public boolean isCustomizing() {
return mView.isCustomizing();
}
/** */
public void show(int x, int y, boolean immediate) {
if (!mView.isShown()) {
setTileSpecs();
if (immediate) {
mView.showImmediately();
} else {
mView.show(x, y, mTileAdapter);
mUiEventLogger.log(QSEditEvent.QS_EDIT_OPEN);
}
mTileQueryHelper.queryTiles(mQsTileHost);
mKeyguardStateController.addCallback(mKeyguardCallback);
mView.updateNavColors(mLightBarController);
}
}
/** */
public void setQs(QSFragment qsFragment) {
mView.setQs(qsFragment);
}
/** */
public void restoreInstanceState(Bundle savedInstanceState) {
boolean customizing = savedInstanceState.getBoolean(EXTRA_QS_CUSTOMIZING);
if (customizing) {
mView.setVisibility(View.VISIBLE);
mView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft,
int oldTop, int oldRight, int oldBottom) {
mView.removeOnLayoutChangeListener(this);
show(0, 0, true);
}
});
}
}
/** */
public void saveInstanceState(Bundle outState) {
if (mView.isShown()) {
mKeyguardStateController.removeCallback(mKeyguardCallback);
}
outState.putBoolean(EXTRA_QS_CUSTOMIZING, mView.isCustomizing());
}
/** */
public void setEditLocation(int x, int y) {
mView.setEditLocation(x, y);
}
/** */
public void setContainer(NotificationsQuickSettingsContainer container) {
mView.setContainer(container);
}
// TODO(b/168904199): remove this.
public QSCustomizer getView() {
return mView;
}
public boolean isShown() {
return mView.isShown();
}
/** Hice the customizer. */
public void hide() {
final boolean animate = mScreenLifecycle.getScreenState() != ScreenLifecycle.SCREEN_OFF;
if (mView.isShown()) {
mUiEventLogger.log(QSEditEvent.QS_EDIT_CLOSED);
mToolbar.dismissPopupMenus();
mView.setCustomizing(false);
save();
mView.hide(animate);
mView.updateNavColors(mLightBarController);
mKeyguardStateController.removeCallback(mKeyguardCallback);
}
}
private void save() {
if (mTileQueryHelper.isFinished()) {
mTileAdapter.saveSpecs(mQsTileHost);
}
}
private void setTileSpecs() {
List<String> specs = new ArrayList<>();
for (QSTile tile : mQsTileHost.getTiles()) {
specs.add(tile.getTileSpec());
}
mTileAdapter.setTileSpecs(specs);
}
}

View File

@@ -46,12 +46,17 @@ import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.customize.TileAdapter.Holder;
import com.android.systemui.qs.customize.TileQueryHelper.TileInfo;
import com.android.systemui.qs.customize.TileQueryHelper.TileStateListener;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tileimpl.QSIconViewImpl;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
/** */
@QSScope
public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileStateListener {
private static final long DRAG_LENGTH = 100;
private static final float DRAG_SCALE = 1.2f;
@@ -78,6 +83,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
private final ItemDecoration mDecoration;
private final MarginTileDecoration mMarginDecoration;
private final int mMinNumTiles;
private final QSTileHost mHost;
private int mEditIndex;
private int mTileDividerIndex;
private int mFocusIndex;
@@ -89,13 +95,14 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
private Holder mCurrentDrag;
private int mAccessibilityAction = ACTION_NONE;
private int mAccessibilityFromIndex;
private QSTileHost mHost;
private final UiEventLogger mUiEventLogger;
private final AccessibilityDelegateCompat mAccessibilityDelegate;
private RecyclerView mRecyclerView;
public TileAdapter(Context context, UiEventLogger uiEventLogger) {
@Inject
public TileAdapter(Context context, QSTileHost qsHost, UiEventLogger uiEventLogger) {
mContext = context;
mHost = qsHost;
mUiEventLogger = uiEventLogger;
mItemTouchHelper = new ItemTouchHelper(mCallbacks);
mDecoration = new TileItemDecoration(context);
@@ -114,10 +121,6 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
mRecyclerView = null;
}
public void setHost(QSTileHost host) {
mHost = host;
}
public ItemTouchHelper getItemTouchHelper() {
return mItemTouchHelper;
}
@@ -154,9 +157,10 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
mAccessibilityAction = ACTION_NONE;
}
public void resetTileSpecs(QSTileHost host, List<String> specs) {
/** */
public void resetTileSpecs(List<String> specs) {
// Notify the host so the tiles get removed callbacks.
host.changeTiles(mCurrentSpecs, specs);
mHost.changeTiles(mCurrentSpecs, specs);
setTileSpecs(specs);
}

View File

@@ -37,6 +37,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.qs.QSTile.State;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.external.CustomTile;
import com.android.systemui.qs.tileimpl.QSTileImpl.DrawableIcon;
import com.android.systemui.settings.UserTracker;
@@ -50,6 +51,8 @@ import java.util.concurrent.Executor;
import javax.inject.Inject;
/** */
@QSScope
public class TileQueryHelper {
private static final String TAG = "TileQueryHelper";

View File

@@ -22,6 +22,7 @@ import com.android.systemui.qs.QSFooter;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.qs.QuickQSPanelController;
import com.android.systemui.qs.customize.QSCustomizerController;
import dagger.BindsInstance;
import dagger.Subcomponent;
@@ -32,6 +33,7 @@ import dagger.Subcomponent;
@Subcomponent(modules = {QSFragmentModule.class})
@QSScope
public interface QSFragmentComponent {
/** Factory for building a {@link QSFragmentComponent}. */
@Subcomponent.Factory
interface Factory {
@@ -52,4 +54,7 @@ public interface QSFragmentComponent {
/** Construct a {@link QSFooter} */
QSFooter getQSFooter();
/** Construct a {@link QSCustomizerController}. */
QSCustomizerController getQSCustomizerController();
}

View File

@@ -29,6 +29,7 @@ import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QuickQSPanel;
import com.android.systemui.qs.QuickStatusBarHeader;
import com.android.systemui.qs.customize.QSCustomizer;
import dagger.Binds;
import dagger.Module;
@@ -87,4 +88,11 @@ public interface QSFragmentModule {
qsFooterViewController.init();
return qsFooterViewController;
}
/** */
@Provides
@QSScope
static QSCustomizer providesQSCutomizer(@RootView View view) {
return view.findViewById(R.id.qs_customize);
}
}

View File

@@ -26,7 +26,6 @@ import android.view.View;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QuickQSPanel;
import com.android.systemui.qs.customize.QSCustomizer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import java.lang.reflect.InvocationTargetException;
@@ -104,11 +103,6 @@ public class InjectionInflationController {
* Creates the QuickQSPanel.
*/
QuickQSPanel createQuickQSPanel();
/**
* Creates the QSCustomizer.
*/
QSCustomizer createQSCustomizer();
}

View File

@@ -52,7 +52,7 @@ public class QSDetailTest extends SysuiTestCase {
private MetricsLogger mMetricsLogger;
private QSDetail mQsDetail;
private QSPanel mQsPanel;
private QSPanelController mQsPanelController;
private QuickStatusBarHeader mQuickHeader;
private ActivityStarter mActivityStarter;
private DetailAdapter mMockDetailAdapter;
@@ -68,9 +68,9 @@ public class QSDetailTest extends SysuiTestCase {
mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
mActivityStarter = mDependency.injectMockDependency(ActivityStarter.class);
mQsDetail = (QSDetail) LayoutInflater.from(mContext).inflate(R.layout.qs_detail, null);
mQsPanel = mock(QSPanel.class);
mQsPanelController = mock(QSPanelController.class);
mQuickHeader = mock(QuickStatusBarHeader.class);
mQsDetail.setQsPanel(mQsPanel, mQuickHeader, mock(QSFooter.class));
mQsDetail.setQsPanel(mQsPanelController, mQuickHeader, mock(QSFooter.class));
mMockDetailAdapter = mock(DetailAdapter.class);
when(mMockDetailAdapter.createDetailView(any(), any(), any()))

View File

@@ -38,6 +38,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTileView;
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import org.junit.Before;
@@ -61,6 +62,8 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
@Mock
private QSTileHost mQSTileHost;
@Mock
private QSCustomizerController mQSCustomizerController;
@Mock
private MediaHost mMediaHost;
@Mock
private MetricsLogger mMetricsLogger;
@@ -76,9 +79,9 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
/** Implementation needed to ensure we have a reflectively-available class name. */
private static class TestableQSPanelControllerBase extends QSPanelControllerBase<QSPanel> {
protected TestableQSPanelControllerBase(QSPanel view, QSTileHost host,
MetricsLogger metricsLogger,
QSCustomizerController qsCustomizerController, MetricsLogger metricsLogger,
UiEventLogger uiEventLogger, DumpManager dumpManager) {
super(view, host, metricsLogger, uiEventLogger, dumpManager);
super(view, host, qsCustomizerController, metricsLogger, uiEventLogger, dumpManager);
}
}
@@ -95,7 +98,7 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
when(mQSTileHost.createTileView(eq(mQSTile), anyBoolean())).thenReturn(mQSTileView);
mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
mMetricsLogger, mUiEventLogger, mDumpManager);
mQSCustomizerController, mMetricsLogger, mUiEventLogger, mDumpManager);
mController.init();
}

View File

@@ -35,6 +35,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.MediaHost;
import com.android.systemui.plugins.qs.QSTileView;
import com.android.systemui.qs.customize.QSCustomizerController;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.settings.BrightnessController;
import com.android.systemui.settings.ToggleSlider;
@@ -58,6 +59,8 @@ public class QSPanelControllerTest extends SysuiTestCase {
@Mock
private QSTileHost mQSTileHost;
@Mock
private QSCustomizerController mQSCustomizerController;
@Mock
private MediaHost mMediaHost;
@Mock
private MetricsLogger mMetricsLogger;
@@ -91,7 +94,7 @@ public class QSPanelControllerTest extends SysuiTestCase {
.thenReturn(mBrightnessController);
mController = new QSPanelController(mQSPanel, mQSSecurityFooter, mTunerService,
mQSTileHost, mDumpManager, mMetricsLogger, mUiEventLogger,
mQSTileHost, mQSCustomizerController, mDumpManager, mMetricsLogger, mUiEventLogger,
mBrightnessControllerFactory);
mController.init();

View File

@@ -15,7 +15,6 @@
package com.android.systemui.qs.customize;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import android.testing.AndroidTestingRunner;
@@ -31,6 +30,8 @@ import com.android.systemui.qs.QSTileHost;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Collections;
@@ -40,17 +41,20 @@ import java.util.Collections;
public class TileAdapterTest extends SysuiTestCase {
private TileAdapter mTileAdapter;
@Mock
private QSTileHost mQSTileHost;
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
TestableLooper.get(this).runWithLooper(() -> mTileAdapter =
new TileAdapter(mContext, new UiEventLoggerFake()));
new TileAdapter(mContext, mQSTileHost, new UiEventLoggerFake()));
}
@Test
public void testResetNotifiesHost() {
QSTileHost host = mock(QSTileHost.class);
mTileAdapter.resetTileSpecs(host, Collections.emptyList());
verify(host).changeTiles(any(), any());
mTileAdapter.resetTileSpecs(Collections.emptyList());
verify(mQSTileHost).changeTiles(any(), any());
}
}