Merge changes from topic "b162525274-kgd-slice-view"

* changes:
  Remove ref to Controller from KeyguardSliceView
  Add KeyguardSliceViewController.
This commit is contained in:
Dave Mankoff
2020-08-24 18:41:28 +00:00
committed by Android (Google) Code Review
20 changed files with 609 additions and 296 deletions

View File

@@ -22,6 +22,7 @@ import android.widget.RelativeLayout;
import android.widget.TextClock;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.keyguard.dagger.KeyguardStatusViewScope;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.plugins.ClockPlugin;
@@ -36,6 +37,7 @@ import java.util.TimeZone;
/**
* Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
*/
@KeyguardStatusViewScope
public class KeyguardClockSwitch extends RelativeLayout {
private static final String TAG = "KeyguardClockSwitch";

View File

@@ -34,10 +34,11 @@ import javax.inject.Inject;
public class KeyguardClockSwitchController {
private static final boolean CUSTOM_CLOCKS_ENABLED = true;
private final KeyguardClockSwitch mView;
private final StatusBarStateController mStatusBarStateController;
private final SysuiColorExtractor mColorExtractor;
private final ClockManager mClockManager;
private KeyguardClockSwitch mView;
private final KeyguardSliceViewController mKeyguardSliceViewController;
private final StatusBarStateController.StateListener mStateListener =
new StatusBarStateController.StateListener() {
@@ -52,9 +53,13 @@ public class KeyguardClockSwitchController {
*
* The color palette changes when the wallpaper is changed.
*/
private final ColorExtractor.OnColorsChangedListener mColorsListener = (extractor, which) -> {
if ((which & WallpaperManager.FLAG_LOCK) != 0) {
mView.updateColors(getGradientColors());
private final ColorExtractor.OnColorsChangedListener mColorsListener =
new ColorExtractor.OnColorsChangedListener() {
@Override
public void onColorsChanged(ColorExtractor extractor, int which) {
if ((which & WallpaperManager.FLAG_LOCK) != 0) {
mView.updateColors(getGradientColors());
}
}
};
@@ -84,22 +89,27 @@ public class KeyguardClockSwitchController {
};
@Inject
public KeyguardClockSwitchController(StatusBarStateController statusBarStateController,
SysuiColorExtractor colorExtractor, ClockManager clockManager) {
public KeyguardClockSwitchController(KeyguardClockSwitch keyguardClockSwitch,
StatusBarStateController statusBarStateController,
SysuiColorExtractor colorExtractor, ClockManager clockManager,
KeyguardSliceViewController keyguardSliceViewController) {
mView = keyguardClockSwitch;
mStatusBarStateController = statusBarStateController;
mColorExtractor = colorExtractor;
mClockManager = clockManager;
mKeyguardSliceViewController = keyguardSliceViewController;
}
/**
* Attach the controller to the view it relates to.
*/
public void attach(KeyguardClockSwitch view) {
mView = view;
public void init() {
if (mView.isAttachedToWindow()) {
mOnAttachStateChangeListener.onViewAttachedToWindow(mView);
}
mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
mKeyguardSliceViewController.init();
}
/**

View File

@@ -34,12 +34,15 @@ import android.view.View;
import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.util.InjectionInflationController;
import javax.inject.Inject;
public class KeyguardDisplayManager {
protected static final String TAG = "KeyguardDisplayManager";
private static boolean DEBUG = KeyguardConstants.DEBUG;
@@ -47,6 +50,7 @@ public class KeyguardDisplayManager {
private final MediaRouter mMediaRouter;
private final DisplayManager mDisplayService;
private final InjectionInflationController mInjectableInflater;
private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
private final Context mContext;
private boolean mShowing;
@@ -86,10 +90,13 @@ public class KeyguardDisplayManager {
}
};
@Inject
public KeyguardDisplayManager(Context context,
InjectionInflationController injectableInflater) {
InjectionInflationController injectableInflater,
KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory) {
mContext = context;
mInjectableInflater = injectableInflater;
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
mMediaRouter = mContext.getSystemService(MediaRouter.class);
mDisplayService = mContext.getSystemService(DisplayManager.class);
mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */);
@@ -124,6 +131,7 @@ public class KeyguardDisplayManager {
Presentation presentation = mPresentations.get(displayId);
if (presentation == null) {
final Presentation newPresentation = new KeyguardPresentation(mContext, display,
mKeyguardStatusViewComponentFactory,
mInjectableInflater.injectable(LayoutInflater.from(mContext)));
newPresentation.setOnDismissListener(dialog -> {
if (newPresentation.equals(mPresentations.get(displayId))) {
@@ -241,7 +249,9 @@ public class KeyguardDisplayManager {
static final class KeyguardPresentation extends Presentation {
private static final int VIDEO_SAFE_REGION = 80; // Percentage of display width & height
private static final int MOVE_CLOCK_TIMEOUT = 10000; // 10s
private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
private final LayoutInflater mInjectableLayoutInflater;
private KeyguardClockSwitchController mKeyguardClockSwitchController;
private View mClock;
private int mUsableWidth;
private int mUsableHeight;
@@ -259,8 +269,10 @@ public class KeyguardDisplayManager {
};
KeyguardPresentation(Context context, Display display,
KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory,
LayoutInflater injectionLayoutInflater) {
super(context, display, R.style.Theme_SystemUI_KeyguardPresentation);
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
mInjectableLayoutInflater = injectionLayoutInflater;
getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
setCancelable(false);
@@ -302,6 +314,12 @@ public class KeyguardDisplayManager {
// Avoid screen burn in
mClock.post(mMoveTextRunnable);
mKeyguardClockSwitchController = mKeyguardStatusViewComponentFactory
.build(findViewById(R.id.clock))
.getKeyguardClockSwitchController();
mKeyguardClockSwitchController.init();
}
}
}

View File

@@ -16,12 +16,6 @@
package com.android.keyguard;
import static android.app.slice.Slice.HINT_LIST_ITEM;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
@@ -35,28 +29,19 @@ import android.graphics.drawable.Drawable;
import android.graphics.text.LineBreaker;
import android.net.Uri;
import android.os.Trace;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.Display;
import android.view.View;
import android.view.animation.Animation;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import androidx.slice.Slice;
import androidx.slice.SliceItem;
import androidx.slice.SliceViewManager;
import androidx.slice.core.SliceQuery;
import androidx.slice.widget.ListContent;
import androidx.slice.widget.RowContent;
import androidx.slice.widget.SliceContent;
import androidx.slice.widget.SliceLiveData;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
@@ -64,70 +49,49 @@ import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.KeyguardSliceProvider;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import java.util.Map;
/**
* View visible under the clock on the lock screen and AoD.
*/
public class KeyguardSliceView extends LinearLayout implements View.OnClickListener,
Observer<Slice>, TunerService.Tunable, ConfigurationController.ConfigurationListener {
public class KeyguardSliceView extends LinearLayout {
private static final String TAG = "KeyguardSliceView";
public static final int DEFAULT_ANIM_DURATION = 550;
private final HashMap<View, PendingIntent> mClickActions;
private final ActivityStarter mActivityStarter;
private final ConfigurationController mConfigurationController;
private final LayoutTransition mLayoutTransition;
private final TunerService mTunerService;
private Uri mKeyguardSliceUri;
@VisibleForTesting
TextView mTitle;
private Row mRow;
private int mTextColor;
private float mDarkAmount = 0;
private LiveData<Slice> mLiveData;
private int mDisplayId = INVALID_DISPLAY;
private int mIconSize;
private int mIconSizeWithHeader;
/**
* Runnable called whenever the view contents change.
*/
private Runnable mContentChangeListener;
private Slice mSlice;
private boolean mHasHeader;
private final int mRowWithHeaderPadding;
private final int mRowPadding;
private float mRowTextSize;
private float mRowWithHeaderTextSize;
private View.OnClickListener mOnClickListener;
@Inject
public KeyguardSliceView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
ActivityStarter activityStarter, ConfigurationController configurationController,
TunerService tunerService, @Main Resources resources) {
public KeyguardSliceView(Context context, AttributeSet attrs) {
super(context, attrs);
mTunerService = tunerService;
mClickActions = new HashMap<>();
Resources resources = context.getResources();
mRowPadding = resources.getDimensionPixelSize(R.dimen.subtitle_clock_padding);
mRowWithHeaderPadding = resources.getDimensionPixelSize(R.dimen.header_subtitle_padding);
mActivityStarter = activityStarter;
mConfigurationController = configurationController;
mLayoutTransition = new LayoutTransition();
mLayoutTransition.setStagger(LayoutTransition.CHANGE_APPEARING, DEFAULT_ANIM_DURATION / 2);
@@ -153,38 +117,9 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
R.dimen.widget_label_font_size);
mRowWithHeaderTextSize = mContext.getResources().getDimensionPixelSize(
R.dimen.header_row_font_size);
mTitle.setOnClickListener(this);
mTitle.setBreakStrategy(LineBreaker.BREAK_STRATEGY_BALANCED);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
Display display = getDisplay();
if (display != null) {
mDisplayId = display.getDisplayId();
}
mTunerService.addTunable(this, Settings.Secure.KEYGUARD_SLICE_URI);
// Make sure we always have the most current slice
if (mDisplayId == DEFAULT_DISPLAY) {
mLiveData.observeForever(this);
}
mConfigurationController.addCallback(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
// TODO(b/117344873) Remove below work around after this issue be fixed.
if (mDisplayId == DEFAULT_DISPLAY) {
mLiveData.removeObserver(this);
}
mTunerService.removeTunable(this);
mConfigurationController.removeCallback(this);
}
@Override
public void onVisibilityAggregated(boolean isVisible) {
super.onVisibilityAggregated(isVisible);
@@ -198,44 +133,31 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
return mHasHeader;
}
private void showSlice() {
Trace.beginSection("KeyguardSliceView#showSlice");
if (mSlice == null) {
mTitle.setVisibility(GONE);
mRow.setVisibility(GONE);
mHasHeader = false;
if (mContentChangeListener != null) {
mContentChangeListener.run();
}
Trace.endSection();
return;
void hideSlice() {
mTitle.setVisibility(GONE);
mRow.setVisibility(GONE);
mHasHeader = false;
if (mContentChangeListener != null) {
mContentChangeListener.run();
}
mClickActions.clear();
}
Map<View, PendingIntent> showSlice(RowContent header, List<SliceContent> subItems) {
Trace.beginSection("KeyguardSliceView#showSlice");
mHasHeader = header != null;
Map<View, PendingIntent> clickActions = new HashMap<>();
ListContent lc = new ListContent(getContext(), mSlice);
SliceContent headerContent = lc.getHeader();
mHasHeader = headerContent != null && !headerContent.getSliceItem().hasHint(HINT_LIST_ITEM);
List<SliceContent> subItems = new ArrayList<>();
for (int i = 0; i < lc.getRowItems().size(); i++) {
SliceContent subItem = lc.getRowItems().get(i);
String itemUri = subItem.getSliceItem().getSlice().getUri().toString();
// Filter out the action row
if (!KeyguardSliceProvider.KEYGUARD_ACTION_URI.equals(itemUri)) {
subItems.add(subItem);
}
}
if (!mHasHeader) {
mTitle.setVisibility(GONE);
} else {
mTitle.setVisibility(VISIBLE);
RowContent header = lc.getHeader();
SliceItem mainTitle = header.getTitleItem();
CharSequence title = mainTitle != null ? mainTitle.getText() : null;
mTitle.setText(title);
if (header.getPrimaryAction() != null
&& header.getPrimaryAction().getAction() != null) {
mClickActions.put(mTitle, header.getPrimaryAction().getAction());
clickActions.put(mTitle, header.getPrimaryAction().getAction());
}
}
@@ -265,7 +187,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
if (rc.getPrimaryAction() != null) {
pendingIntent = rc.getPrimaryAction().getAction();
}
mClickActions.put(button, pendingIntent);
clickActions.put(button, pendingIntent);
final SliceItem titleItem = rc.getTitleItem();
button.setText(titleItem == null ? null : titleItem.getText());
@@ -286,14 +208,14 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
}
}
button.setCompoundDrawables(iconDrawable, null, null, null);
button.setOnClickListener(this);
button.setOnClickListener(mOnClickListener);
button.setClickable(pendingIntent != null);
}
// Removing old views
for (int i = 0; i < mRow.getChildCount(); i++) {
View child = mRow.getChildAt(i);
if (!mClickActions.containsKey(child)) {
if (!clickActions.containsKey(child)) {
mRow.removeView(child);
i--;
}
@@ -303,6 +225,8 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
mContentChangeListener.run();
}
Trace.endSection();
return clickActions;
}
public void setDarkAmount(float darkAmount) {
@@ -323,14 +247,6 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
}
}
@Override
public void onClick(View v) {
final PendingIntent action = mClickActions.get(v);
if (action != null) {
mActivityStarter.startPendingIntentDismissingKeyguard(action);
}
}
/**
* Runnable that gets invoked every time the title or the row visibility changes.
* @param contentChangeListener The listener.
@@ -339,43 +255,6 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
mContentChangeListener = contentChangeListener;
}
/**
* LiveData observer lifecycle.
* @param slice the new slice content.
*/
@Override
public void onChanged(Slice slice) {
mSlice = slice;
showSlice();
}
@Override
public void onTuningChanged(String key, String newValue) {
setupUri(newValue);
}
/**
* Sets the slice provider Uri.
*/
public void setupUri(String uriString) {
if (uriString == null) {
uriString = KeyguardSliceProvider.KEYGUARD_SLICE_URI;
}
boolean wasObserving = false;
if (mLiveData != null && mLiveData.hasActiveObservers()) {
wasObserving = true;
mLiveData.removeObserver(this);
}
mKeyguardSliceUri = Uri.parse(uriString);
mLiveData = SliceLiveData.fromUri(mContext, mKeyguardSliceUri);
if (wasObserving) {
mLiveData.observeForever(this);
}
}
@VisibleForTesting
int getTextColor() {
return ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount);
@@ -387,8 +266,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
updateTextColors();
}
@Override
public void onDensityOrFontScaleChanged() {
void onDensityOrFontScaleChanged() {
mIconSize = mContext.getResources().getDimensionPixelSize(R.dimen.widget_icon_size);
mIconSizeWithHeader = (int) mContext.getResources().getDimension(R.dimen.header_icon_size);
mRowTextSize = mContext.getResources().getDimensionPixelSize(
@@ -397,37 +275,21 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
R.dimen.header_row_font_size);
}
public void refresh() {
Slice slice;
Trace.beginSection("KeyguardSliceView#refresh");
// We can optimize performance and avoid binder calls when we know that we're bound
// to a Slice on the same process.
if (KeyguardSliceProvider.KEYGUARD_SLICE_URI.equals(mKeyguardSliceUri.toString())) {
KeyguardSliceProvider instance = KeyguardSliceProvider.getAttachedInstance();
if (instance != null) {
slice = instance.onBindSlice(mKeyguardSliceUri);
} else {
Log.w(TAG, "Keyguard slice not bound yet?");
slice = null;
}
} else {
slice = SliceViewManager.getInstance(getContext()).bindSlice(mKeyguardSliceUri);
}
onChanged(slice);
Trace.endSection();
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardSliceView:");
pw.println(" mClickActions: " + mClickActions);
pw.println(" mTitle: " + (mTitle == null ? "null" : mTitle.getVisibility() == VISIBLE));
pw.println(" mRow: " + (mRow == null ? "null" : mRow.getVisibility() == VISIBLE));
pw.println(" mTextColor: " + Integer.toHexString(mTextColor));
pw.println(" mDarkAmount: " + mDarkAmount);
pw.println(" mSlice: " + mSlice);
pw.println(" mHasHeader: " + mHasHeader);
}
@Override
public void setOnClickListener(View.OnClickListener onClickListener) {
mOnClickListener = onClickListener;
mTitle.setOnClickListener(onClickListener);
}
public static class Row extends LinearLayout {
/**

View File

@@ -0,0 +1,234 @@
/*
* 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.keyguard;
import static android.app.slice.Slice.HINT_LIST_ITEM;
import static android.view.Display.DEFAULT_DISPLAY;
import android.app.PendingIntent;
import android.net.Uri;
import android.os.Trace;
import android.provider.Settings;
import android.util.Log;
import android.view.Display;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import androidx.slice.Slice;
import androidx.slice.SliceViewManager;
import androidx.slice.widget.ListContent;
import androidx.slice.widget.RowContent;
import androidx.slice.widget.SliceContent;
import androidx.slice.widget.SliceLiveData;
import com.android.keyguard.dagger.KeyguardStatusViewScope;
import com.android.systemui.Dumpable;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.inject.Inject;
/** Controller for a {@link KeyguardSliceView}. */
@KeyguardStatusViewScope
public class KeyguardSliceViewController implements Dumpable {
private static final String TAG = "KeyguardSliceViewCtrl";
private final KeyguardSliceView mView;
private final KeyguardStatusView mKeyguardStatusView;
private final ActivityStarter mActivityStarter;
private final ConfigurationController mConfigurationController;
private final TunerService mTunerService;
private final DumpManager mDumpManager;
private int mDisplayId;
private LiveData<Slice> mLiveData;
private Uri mKeyguardSliceUri;
private Slice mSlice;
private Map<View, PendingIntent> mClickActions;
private final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
Display display = mView.getDisplay();
if (display != null) {
mDisplayId = display.getDisplayId();
}
mTunerService.addTunable(mTunable, Settings.Secure.KEYGUARD_SLICE_URI);
// Make sure we always have the most current slice
if (mDisplayId == DEFAULT_DISPLAY && mLiveData != null) {
mLiveData.observeForever(mObserver);
}
mConfigurationController.addCallback(mConfigurationListener);
mDumpManager.registerDumpable(TAG, KeyguardSliceViewController.this);
}
@Override
public void onViewDetachedFromWindow(View v) {
// TODO(b/117344873) Remove below work around after this issue be fixed.
if (mDisplayId == DEFAULT_DISPLAY) {
mLiveData.removeObserver(mObserver);
}
mTunerService.removeTunable(mTunable);
mConfigurationController.removeCallback(mConfigurationListener);
mDumpManager.unregisterDumpable(TAG);
}
};
TunerService.Tunable mTunable = (key, newValue) -> setupUri(newValue);
ConfigurationController.ConfigurationListener mConfigurationListener =
new ConfigurationController.ConfigurationListener() {
@Override
public void onDensityOrFontScaleChanged() {
mView.onDensityOrFontScaleChanged();
}
};
Observer<Slice> mObserver = new Observer<Slice>() {
@Override
public void onChanged(Slice slice) {
mSlice = slice;
showSlice(slice);
}
};
private View.OnClickListener mOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
final PendingIntent action = mClickActions.get(v);
if (action != null && mActivityStarter != null) {
mActivityStarter.startPendingIntentDismissingKeyguard(action);
}
}
};
@Inject
public KeyguardSliceViewController(KeyguardSliceView keyguardSliceView,
KeyguardStatusView keyguardStatusView, ActivityStarter activityStarter,
ConfigurationController configurationController, TunerService tunerService,
DumpManager dumpManager) {
mView = keyguardSliceView;
mKeyguardStatusView = keyguardStatusView;
mActivityStarter = activityStarter;
mConfigurationController = configurationController;
mTunerService = tunerService;
mDumpManager = dumpManager;
}
/** Initialize the controller. */
public void init() {
if (mView.isAttachedToWindow()) {
mOnAttachStateChangeListener.onViewAttachedToWindow(mView);
}
mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
mView.setOnClickListener(mOnClickListener);
// TODO: remove the line below.
mKeyguardStatusView.setKeyguardSliceViewController(this);
}
/**
* Sets the slice provider Uri.
*/
public void setupUri(String uriString) {
if (uriString == null) {
uriString = KeyguardSliceProvider.KEYGUARD_SLICE_URI;
}
boolean wasObserving = false;
if (mLiveData != null && mLiveData.hasActiveObservers()) {
wasObserving = true;
mLiveData.removeObserver(mObserver);
}
mKeyguardSliceUri = Uri.parse(uriString);
mLiveData = SliceLiveData.fromUri(mView.getContext(), mKeyguardSliceUri);
if (wasObserving) {
mLiveData.observeForever(mObserver);
}
}
/**
* Update contents of the view.
*/
public void refresh() {
Slice slice;
Trace.beginSection("KeyguardSliceViewController#refresh");
// We can optimize performance and avoid binder calls when we know that we're bound
// to a Slice on the same process.
if (KeyguardSliceProvider.KEYGUARD_SLICE_URI.equals(mKeyguardSliceUri.toString())) {
KeyguardSliceProvider instance = KeyguardSliceProvider.getAttachedInstance();
if (instance != null) {
slice = instance.onBindSlice(mKeyguardSliceUri);
} else {
Log.w(TAG, "Keyguard slice not bound yet?");
slice = null;
}
} else {
// TODO: Make SliceViewManager injectable
slice = SliceViewManager.getInstance(mView.getContext()).bindSlice(mKeyguardSliceUri);
}
mObserver.onChanged(slice);
Trace.endSection();
}
void showSlice(Slice slice) {
Trace.beginSection("KeyguardSliceViewController#showSlice");
if (slice == null) {
mView.hideSlice();
Trace.endSection();
return;
}
ListContent lc = new ListContent(slice);
RowContent headerContent = lc.getHeader();
boolean hasHeader =
headerContent != null && !headerContent.getSliceItem().hasHint(HINT_LIST_ITEM);
List<SliceContent> subItems = lc.getRowItems().stream().filter(sliceContent -> {
String itemUri = sliceContent.getSliceItem().getSlice().getUri().toString();
// Filter out the action row
return !KeyguardSliceProvider.KEYGUARD_ACTION_URI.equals(itemUri);
}).collect(Collectors.toList());
mClickActions = mView.showSlice(hasHeader ? headerContent : null, subItems);
Trace.endSection();
}
@Override
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.println(" mSlice: " + mSlice);
pw.println(" mClickActions: " + mClickActions);
}
}

View File

@@ -32,7 +32,6 @@ import android.util.Slog;
import android.util.TypedValue;
import android.view.View;
import android.widget.GridLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.core.graphics.ColorUtils;
@@ -56,7 +55,6 @@ public class KeyguardStatusView extends GridLayout implements
private final LockPatternUtils mLockPatternUtils;
private final IActivityManager mIActivityManager;
private LinearLayout mStatusViewContainer;
private TextView mLogoutView;
private KeyguardClockSwitch mClockView;
private TextView mOwnerInfo;
@@ -64,6 +62,7 @@ public class KeyguardStatusView extends GridLayout implements
private View mNotificationIcons;
private Runnable mPendingMarqueeStart;
private Handler mHandler;
private KeyguardSliceViewController mKeyguardSliceViewController;
private boolean mPulsing;
private float mDarkAmount = 0;
@@ -179,7 +178,6 @@ public class KeyguardStatusView extends GridLayout implements
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mStatusViewContainer = findViewById(R.id.status_view_container);
mLogoutView = findViewById(R.id.logout);
mNotificationIcons = findViewById(R.id.clock_notification_icon_container);
if (mLogoutView != null) {
@@ -250,7 +248,7 @@ public class KeyguardStatusView extends GridLayout implements
public void dozeTimeTick() {
refreshTime();
mKeyguardSlice.refresh();
mKeyguardSliceViewController.refresh();
}
private void refreshTime() {
@@ -456,4 +454,9 @@ public class KeyguardStatusView extends GridLayout implements
Log.e(TAG, "Failed to logout user", re);
}
}
// TODO: remove this method when a controller is available.
void setKeyguardSliceViewController(KeyguardSliceViewController keyguardSliceViewController) {
mKeyguardSliceViewController = keyguardSliceViewController;
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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.keyguard.dagger;
import com.android.keyguard.KeyguardClockSwitchController;
import com.android.keyguard.KeyguardStatusView;
import dagger.BindsInstance;
import dagger.Subcomponent;
/**
* Subcomponent for helping work with KeyguardStatusView and its children.
*/
@Subcomponent(modules = {KeyguardStatusViewModule.class})
@KeyguardStatusViewScope
public interface KeyguardStatusViewComponent {
/** Simple factory for {@link KeyguardStatusViewComponent}. */
@Subcomponent.Factory
interface Factory {
KeyguardStatusViewComponent build(@BindsInstance KeyguardStatusView presentation);
}
/** Builds a {@link com.android.keyguard.KeyguardClockSwitchController}. */
KeyguardClockSwitchController getKeyguardClockSwitchController();
}

View File

@@ -0,0 +1,39 @@
/*
* 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.keyguard.dagger;
import com.android.keyguard.KeyguardClockSwitch;
import com.android.keyguard.KeyguardSliceView;
import com.android.keyguard.KeyguardStatusView;
import com.android.systemui.R;
import dagger.Module;
import dagger.Provides;
/** Dagger module for {@link KeyguardStatusViewComponent}. */
@Module
public abstract class KeyguardStatusViewModule {
@Provides
static KeyguardClockSwitch getKeyguardClockSwitch(KeyguardStatusView keyguardPresentation) {
return keyguardPresentation.findViewById(R.id.keyguard_clock_container);
}
@Provides
static KeyguardSliceView getKeyguardSliceView(KeyguardClockSwitch keyguardClockSwitch) {
return keyguardClockSwitch.findViewById(R.id.keyguard_status_area);
}
}

View File

@@ -0,0 +1,32 @@
/*
* 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.keyguard.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import javax.inject.Scope;
/**
* Scope annotation for singleton items within the StatusBarComponent.
*/
@Documented
@Retention(RUNTIME)
@Scope
public @interface KeyguardStatusViewScope {}

View File

@@ -89,15 +89,14 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.dagger.KeyguardModule;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.InjectionInflationController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -228,7 +227,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
/** TrustManager for letting it know when we change visibility */
private final TrustManager mTrustManager;
private final InjectionInflationController mInjectionInflationController;
/**
* Used to keep the device awake while to ensure the keyguard finishes opening before
@@ -345,7 +343,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
/**
* For managing external displays
*/
private KeyguardDisplayManager mKeyguardDisplayManager;
private final KeyguardDisplayManager mKeyguardDisplayManager;
private final ArrayList<IKeyguardStateCallback> mKeyguardStateCallbacks = new ArrayList<>();
@@ -724,7 +722,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
TrustManager trustManager,
DeviceConfigProxy deviceConfig,
NavigationModeController navigationModeController,
InjectionInflationController injectionInflationController) {
KeyguardDisplayManager keyguardDisplayManager) {
super(context);
mFalsingManager = falsingManager;
mLockPatternUtils = lockPatternUtils;
@@ -735,7 +733,7 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
mUpdateMonitor = keyguardUpdateMonitor;
mPM = powerManager;
mTrustManager = trustManager;
mInjectionInflationController = injectionInflationController;
mKeyguardDisplayManager = keyguardDisplayManager;
dumpManager.registerDumpable(getClass().getName(), this);
mDeviceConfig = deviceConfig;
mShowHomeOverLockscreen = mDeviceConfig.getBoolean(
@@ -775,9 +773,6 @@ public class KeyguardViewMediator extends SystemUI implements Dumpable {
mContext.registerReceiver(mDelayedLockBroadcastReceiver, delayedActionFilter,
SYSTEMUI_PERMISSION, null /* scheduler */);
mKeyguardDisplayManager = new KeyguardDisplayManager(mContext,
mInjectionInflationController);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
KeyguardUpdateMonitor.setCurrentUser(ActivityManager.getCurrentUser());

View File

@@ -26,8 +26,10 @@ import android.os.Handler;
import android.os.PowerManager;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardDisplayManager;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardViewController;
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -43,7 +45,6 @@ import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.KeyguardLiftController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.InjectionInflationController;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.settings.GlobalSettings;
import com.android.systemui.util.settings.SystemSettings;
@@ -58,7 +59,7 @@ import dagger.Provides;
/**
* Dagger Module providing {@link StatusBar}.
*/
@Module
@Module(subcomponents = {KeyguardStatusViewComponent.class})
public class KeyguardModule {
/**
* Provides our instance of KeyguardViewMediator which is considered optional.
@@ -79,7 +80,7 @@ public class KeyguardModule {
@UiBackground Executor uiBgExecutor,
DeviceConfigProxy deviceConfig,
NavigationModeController navigationModeController,
InjectionInflationController injectionInflationController) {
KeyguardDisplayManager keyguardDisplayManager) {
return new KeyguardViewMediator(
context,
falsingManager,
@@ -94,7 +95,8 @@ public class KeyguardModule {
trustManager,
deviceConfig,
navigationModeController,
injectionInflationController);
keyguardDisplayManager
);
}
@SysUISingleton

View File

@@ -68,6 +68,7 @@ import com.android.keyguard.KeyguardClockSwitchController;
import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.DejankUtils;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -129,7 +130,6 @@ import java.util.function.Consumer;
import java.util.function.Function;
import javax.inject.Inject;
import javax.inject.Provider;
@StatusBarComponent.StatusBarScope
public class NotificationPanelViewController extends PanelViewController {
@@ -260,7 +260,7 @@ public class NotificationPanelViewController extends PanelViewController {
private final ConversationNotificationManager mConversationNotificationManager;
private final MediaHierarchyManager mMediaHierarchyManager;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final Provider<KeyguardClockSwitchController> mKeyguardClockSwitchControllerProvider;
private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
// Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card.
// If there are exactly 1 + mMaxKeyguardNotifications, then still shows all notifications
private final int mMaxKeyguardNotifications;
@@ -511,9 +511,9 @@ public class NotificationPanelViewController extends PanelViewController {
MediaHierarchyManager mediaHierarchyManager,
BiometricUnlockController biometricUnlockController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
Provider<KeyguardClockSwitchController> keyguardClockSwitchControllerProvider,
NotificationStackScrollLayoutController notificationStackScrollLayoutController,
NotificationIconAreaController notificationIconAreaController) {
NotificationIconAreaController notificationIconAreaController,
KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
latencyTracker, flingAnimationUtilsBuilder, statusBarTouchableRegionManager);
@@ -525,9 +525,9 @@ public class NotificationPanelViewController extends PanelViewController {
mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
mMediaHierarchyManager = mediaHierarchyManager;
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
mKeyguardClockSwitchControllerProvider = keyguardClockSwitchControllerProvider;
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
mNotificationIconAreaController = notificationIconAreaController;
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
mView.setWillNotDraw(!DEBUG);
mInjectionInflationController = injectionInflationController;
mFalsingManager = falsingManager;
@@ -602,8 +602,10 @@ public class NotificationPanelViewController extends PanelViewController {
mKeyguardStatusView = mView.findViewById(R.id.keyguard_status_view);
KeyguardClockSwitchController keyguardClockSwitchController =
mKeyguardClockSwitchControllerProvider.get();
keyguardClockSwitchController.attach(mView.findViewById(R.id.keyguard_clock_container));
mKeyguardStatusViewComponentFactory
.build(mKeyguardStatusView)
.getKeyguardClockSwitchController();
keyguardClockSwitchController.init();
mBigClockContainer = mView.findViewById(R.id.big_clock_container);
keyguardClockSwitchController.setBigClockContainer(mBigClockContainer);
@@ -733,8 +735,10 @@ public class NotificationPanelViewController extends PanelViewController {
// Re-associate the clock container with the keyguard clock switch.
mBigClockContainer.removeAllViews();
KeyguardClockSwitchController keyguardClockSwitchController =
mKeyguardClockSwitchControllerProvider.get();
keyguardClockSwitchController.attach(mView.findViewById(R.id.keyguard_clock_container));
mKeyguardStatusViewComponentFactory
.build(mKeyguardStatusView)
.getKeyguardClockSwitchController();
keyguardClockSwitchController.init();
keyguardClockSwitchController.setBigClockContainer(mBigClockContainer);
// Update keyguard bottom area

View File

@@ -24,7 +24,6 @@ import android.view.LayoutInflater;
import android.view.View;
import com.android.keyguard.KeyguardMessageArea;
import com.android.keyguard.KeyguardSliceView;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.qs.QSFooterImpl;
import com.android.systemui.qs.QSPanel;
@@ -108,11 +107,6 @@ public class InjectionInflationController {
*/
NotificationStackScrollLayout createNotificationStackScrollLayout();
/**
* Creates the KeyguardSliceView.
*/
KeyguardSliceView createKeyguardSliceView();
/**
* Creates the KeyguardMessageArea.
*/

View File

@@ -62,6 +62,8 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
private ClockPlugin mClockPlugin;
@Mock
ColorExtractor.GradientColors mGradientColors;
@Mock
KeyguardSliceViewController mKeyguardSliceViewController;
private KeyguardClockSwitchController mController;
@@ -69,28 +71,30 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
public void setup() {
MockitoAnnotations.initMocks(this);
mController = new KeyguardClockSwitchController(
mStatusBarStateController, mColorExtractor, mClockManager);
when(mView.isAttachedToWindow()).thenReturn(true);
mController = new KeyguardClockSwitchController(
mView, mStatusBarStateController, mColorExtractor, mClockManager,
mKeyguardSliceViewController);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
when(mColorExtractor.getColors(anyInt())).thenReturn(mGradientColors);
}
@Test
public void testAttach_viewAlreadyAttached() {
mController.attach(mView);
public void testInit_viewAlreadyAttached() {
mController.init();
verifyAttachment(times(1));
}
@Test
public void testAttach_viewNotYetAttached() {
public void testInit_viewNotYetAttached() {
ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor =
ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
when(mView.isAttachedToWindow()).thenReturn(false);
mController.attach(mView);
mController.init();
verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture());
verifyAttachment(never());
@@ -100,12 +104,17 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
verifyAttachment(times(1));
}
@Test
public void testInitSubControllers() {
mController.init();
verify(mKeyguardSliceViewController).init();
}
@Test
public void testAttach_viewDetached() {
public void testInit_viewDetached() {
ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor =
ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
mController.attach(mView);
mController.init();
verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture());
verifyAttachment(times(1));
@@ -122,7 +131,7 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
public void testBigClockPassesStatusBarState() {
ViewGroup testView = new FrameLayout(mContext);
mController.attach(mView);
mController.init();
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
mController.setBigClockContainer(testView);
verify(mView).setBigClockContainer(testView, StatusBarState.SHADE);
@@ -143,7 +152,7 @@ public class KeyguardClockSwitchControllerTest extends SysuiTestCase {
ArgumentCaptor<ClockManager.ClockChangedListener> listenerArgumentCaptor =
ArgumentCaptor.forClass(ClockManager.ClockChangedListener.class);
mController.attach(mView);
mController.init();
verify(mClockManager).addOnClockChangedListener(listenerArgumentCaptor.capture());
listenerArgumentCaptor.getValue().onClockChanged(mClockPlugin);

View File

@@ -16,6 +16,7 @@
package com.android.keyguard;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -28,6 +29,7 @@ import android.view.View;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardDisplayManager.KeyguardPresentation;
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.R;
import com.android.systemui.SystemUIFactory;
import com.android.systemui.SysuiTestCase;
@@ -51,6 +53,12 @@ public class KeyguardPresentationTest extends SysuiTestCase {
KeyguardSliceView mMockKeyguardSliceView;
@Mock
KeyguardStatusView mMockKeyguardStatusView;
@Mock
private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
@Mock
private KeyguardStatusViewComponent mKeyguardStatusViewComponent;
@Mock
private KeyguardClockSwitchController mKeyguardClockSwitchController;
LayoutInflater mLayoutInflater;
@@ -62,6 +70,11 @@ public class KeyguardPresentationTest extends SysuiTestCase {
when(mMockKeyguardSliceView.getContext()).thenReturn(mContext);
when(mMockKeyguardStatusView.getContext()).thenReturn(mContext);
when(mMockKeyguardStatusView.findViewById(R.id.clock)).thenReturn(mMockKeyguardStatusView);
when(mKeyguardStatusViewComponentFactory.build(any(KeyguardStatusView.class)))
.thenReturn(mKeyguardStatusViewComponent);
when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
.thenReturn(mKeyguardClockSwitchController);
allowTestableLooperAsMainThread();
InjectionInflationController inflationController = new InjectionInflationController(
@@ -99,7 +112,8 @@ public class KeyguardPresentationTest extends SysuiTestCase {
@Test
public void testInflation_doesntCrash() {
KeyguardPresentation keyguardPresentation = new KeyguardPresentation(mContext,
mContext.getDisplayNoVerify(), mLayoutInflater);
mContext.getDisplayNoVerify(), mKeyguardStatusViewComponentFactory,
mLayoutInflater);
keyguardPresentation.onCreate(null /*savedInstanceState */);
}
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2018 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.keyguard;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.View;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper(setAsMainLooper = true)
public class KeyguardSliceViewControllerTest extends SysuiTestCase {
@Mock
private KeyguardSliceView mView;;
@Mock
private KeyguardStatusView mKeyguardStatusView;
@Mock
private TunerService mTunerService;
@Mock
private ConfigurationController mConfigurationController;
@Mock
private ActivityStarter mActivityStarter;
private DumpManager mDumpManager = new DumpManager();
private KeyguardSliceViewController mController;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mView.isAttachedToWindow()).thenReturn(true);
when(mView.getContext()).thenReturn(mContext);
mController = new KeyguardSliceViewController(
mView, mKeyguardStatusView, mActivityStarter, mConfigurationController,
mTunerService, mDumpManager);
mController.setupUri(KeyguardSliceProvider.KEYGUARD_SLICE_URI);
}
@Test
public void refresh_replacesSliceContentAndNotifiesListener() {
mController.refresh();
verify(mView).hideSlice();
}
@Test
public void onAttachedToWindow_registersListeners() {
mController.init();
verify(mTunerService).addTunable(any(TunerService.Tunable.class), anyString());
verify(mConfigurationController).addCallback(
any(ConfigurationController.ConfigurationListener.class));
}
@Test
public void onDetachedFromWindow_unregistersListeners() {
ArgumentCaptor<View.OnAttachStateChangeListener> attachListenerArgumentCaptor =
ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
mController.init();
verify(mView).addOnAttachStateChangeListener(attachListenerArgumentCaptor.capture());
attachListenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView);
verify(mTunerService).removeTunable(any(TunerService.Tunable.class));
verify(mConfigurationController).removeCallback(
any(ConfigurationController.ConfigurationListener.class));
}
}

View File

@@ -15,37 +15,27 @@
*/
package com.android.keyguard;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.net.Uri;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import androidx.slice.Slice;
import androidx.slice.SliceProvider;
import androidx.slice.SliceSpecs;
import androidx.slice.builders.ListBuilder;
import androidx.slice.widget.RowContent;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.keyguard.KeyguardSliceProvider;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
import org.junit.Assert;
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;
@@ -53,46 +43,18 @@ import java.util.HashSet;
import java.util.concurrent.atomic.AtomicBoolean;
@SmallTest
@RunWithLooper
@RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidTestingRunner.class)
public class KeyguardSliceViewTest extends SysuiTestCase {
private KeyguardSliceView mKeyguardSliceView;
private Uri mSliceUri;
@Mock
private TunerService mTunerService;
@Mock
private ConfigurationController mConfigurationController;
@Mock
private ActivityStarter mActivityStarter;
@Mock
private Resources mResources;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
allowTestableLooperAsMainThread();
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
layoutInflater.setPrivateFactory(new LayoutInflater.Factory2() {
@Override
public View onCreateView(View parent, String name, Context context,
AttributeSet attrs) {
return onCreateView(name, context, attrs);
}
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
if ("com.android.keyguard.KeyguardSliceView".equals(name)) {
return new KeyguardSliceView(getContext(), attrs, mActivityStarter,
mConfigurationController, mTunerService, mResources);
}
return null;
}
});
mKeyguardSliceView = (KeyguardSliceView) layoutInflater
.inflate(R.layout.keyguard_status_area, null);
mKeyguardSliceView.setupUri(KeyguardSliceProvider.KEYGUARD_SLICE_URI);
mSliceUri = Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI);
SliceProvider.setSpecs(new HashSet<>(Collections.singletonList(SliceSpecs.LIST)));
}
@@ -100,9 +62,13 @@ public class KeyguardSliceViewTest extends SysuiTestCase {
@Test
public void showSlice_notifiesListener() {
ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY);
builder.setHeader(new ListBuilder.HeaderBuilder().setTitle("header title!"));
Slice slice = builder.build();
RowContent rowContent = new RowContent(slice.getItemArray()[0], 0);
AtomicBoolean notified = new AtomicBoolean();
mKeyguardSliceView.setContentChangeListener(()-> notified.set(true));
mKeyguardSliceView.onChanged(builder.build());
mKeyguardSliceView.showSlice(rowContent, Collections.EMPTY_LIST);
Assert.assertTrue("Listener should be notified about slice changes.",
notified.get());
}
@@ -111,7 +77,7 @@ public class KeyguardSliceViewTest extends SysuiTestCase {
public void showSlice_emptySliceNotifiesListener() {
AtomicBoolean notified = new AtomicBoolean();
mKeyguardSliceView.setContentChangeListener(()-> notified.set(true));
mKeyguardSliceView.onChanged(null);
mKeyguardSliceView.showSlice(null, Collections.EMPTY_LIST);
Assert.assertTrue("Listener should be notified about slice changes.",
notified.get());
}
@@ -119,23 +85,16 @@ public class KeyguardSliceViewTest extends SysuiTestCase {
@Test
public void hasHeader_readsSliceData() {
ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY);
mKeyguardSliceView.onChanged(builder.build());
mKeyguardSliceView.showSlice(null, Collections.EMPTY_LIST);
Assert.assertFalse("View should not have a header", mKeyguardSliceView.hasHeader());
builder.setHeader(new ListBuilder.HeaderBuilder().setTitle("header title!"));
mKeyguardSliceView.onChanged(builder.build());
Slice slice = builder.build();
RowContent rowContent = new RowContent(slice.getItemArray()[0], 0);
mKeyguardSliceView.showSlice(rowContent, Collections.EMPTY_LIST);
Assert.assertTrue("View should have a header", mKeyguardSliceView.hasHeader());
}
@Test
public void refresh_replacesSliceContentAndNotifiesListener() {
AtomicBoolean notified = new AtomicBoolean();
mKeyguardSliceView.setContentChangeListener(()-> notified.set(true));
mKeyguardSliceView.refresh();
Assert.assertTrue("Listener should be notified about slice changes.",
notified.get());
}
@Test
public void getTextColor_whiteTextWhenAOD() {
// Set text color to red since the default is white and test would always pass
@@ -147,18 +106,4 @@ public class KeyguardSliceViewTest extends SysuiTestCase {
Assert.assertEquals("Should be using AOD text color", Color.WHITE,
mKeyguardSliceView.getTextColor());
}
@Test
public void onAttachedToWindow_registersListeners() {
mKeyguardSliceView.onAttachedToWindow();
verify(mTunerService).addTunable(eq(mKeyguardSliceView), anyString());
verify(mConfigurationController).addCallback(eq(mKeyguardSliceView));
}
@Test
public void onDetachedFromWindow_unregistersListeners() {
mKeyguardSliceView.onDetachedFromWindow();
verify(mTunerService).removeTunable(eq(mKeyguardSliceView));
verify(mConfigurationController).removeCallback(eq(mKeyguardSliceView));
}
}

View File

@@ -40,7 +40,8 @@ import org.mockito.Mock;
public class KeyguardStatusViewTest extends SysuiTestCase {
@Mock
KeyguardSliceView mKeyguardSlice;
KeyguardSliceViewController mKeyguardSliceViewController;
@Mock
KeyguardClockSwitch mClockView;
@InjectMocks
@@ -64,7 +65,7 @@ public class KeyguardStatusViewTest extends SysuiTestCase {
@Test
public void dozeTimeTick_updatesSlice() {
mKeyguardStatusView.dozeTimeTick();
verify(mKeyguardSlice).refresh();
verify(mKeyguardSliceViewController).refresh();
}
@Test

View File

@@ -37,6 +37,7 @@ import android.testing.TestableLooper.RunWithLooper;
import androidx.test.filters.SmallTest;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.KeyguardDisplayManager;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
@@ -46,7 +47,6 @@ import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.util.DeviceConfigProxy;
import com.android.systemui.util.DeviceConfigProxyFake;
import com.android.systemui.util.InjectionInflationController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -72,7 +72,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
private @Mock PowerManager mPowerManager;
private @Mock TrustManager mTrustManager;
private @Mock NavigationModeController mNavigationModeController;
private @Mock InjectionInflationController mInjectionInflationController;
private @Mock KeyguardDisplayManager mKeyguardDisplayManager;
private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
@@ -91,7 +91,7 @@ public class KeyguardViewMediatorTest extends SysuiTestCase {
() -> mStatusBarKeyguardViewManager,
mDismissCallbackRegistry, mUpdateMonitor, mDumpManager, mUiBgExecutor,
mPowerManager, mTrustManager, mDeviceConfig, mNavigationModeController,
mInjectionInflationController);
mKeyguardDisplayManager);
mViewMediator.start();
}

View File

@@ -54,6 +54,7 @@ import com.android.keyguard.KeyguardClockSwitch;
import com.android.keyguard.KeyguardClockSwitchController;
import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
@@ -187,10 +188,16 @@ public class NotificationPanelViewTest extends SysuiTestCase {
@Mock
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock
private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
@Mock
private KeyguardStatusViewComponent mKeyguardStatusViewComponent;
@Mock
private KeyguardClockSwitchController mKeyguardClockSwitchController;
@Mock
private NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
private FlingAnimationUtils.Builder mFlingAnimationUtilsBuilder;
private NotificationPanelViewController mNotificationPanelViewController;
private View.AccessibilityDelegate mAccessibiltyDelegate;
@@ -241,6 +248,10 @@ public class NotificationPanelViewTest extends SysuiTestCase {
mock(NotificationRoundnessManager.class),
mStatusBarStateController,
new FalsingManagerFake());
when(mKeyguardStatusViewComponentFactory.build(any()))
.thenReturn(mKeyguardStatusViewComponent);
when(mKeyguardStatusViewComponent.getKeyguardClockSwitchController())
.thenReturn(mKeyguardClockSwitchController);
mNotificationPanelViewController = new NotificationPanelViewController(mView,
mResources,
mInjectionInflationController,
@@ -254,9 +265,9 @@ public class NotificationPanelViewTest extends SysuiTestCase {
flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
mConversationNotificationManager, mMediaHiearchyManager,
mBiometricUnlockController, mStatusBarKeyguardViewManager,
() -> mKeyguardClockSwitchController,
mNotificationStackScrollLayoutController,
mNotificationAreaController);
mNotificationAreaController,
mKeyguardStatusViewComponentFactory);
mNotificationPanelViewController.initDependencies(
mStatusBar,
mGroupManager,