diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index ecf1c2c91770b..5ad8cad8195a7 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -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"; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java index f17f1ca797e01..fe5fcc6fd6322 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java @@ -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(); } /** diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java index 6f19613be28f3..be21d203411e3 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java @@ -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(); } } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index f639c880c97ae..a479bca56c2ac 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -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, 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 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 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 showSlice(RowContent header, List subItems) { + Trace.beginSection("KeyguardSliceView#showSlice"); + mHasHeader = header != null; + Map clickActions = new HashMap<>(); - ListContent lc = new ListContent(getContext(), mSlice); - SliceContent headerContent = lc.getHeader(); - mHasHeader = headerContent != null && !headerContent.getSliceItem().hasHint(HINT_LIST_ITEM); - List 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 { /** diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java new file mode 100644 index 0000000000000..35a2392ba1cf8 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java @@ -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 mLiveData; + private Uri mKeyguardSliceUri; + private Slice mSlice; + private Map 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 mObserver = new Observer() { + @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 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); + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index 4c6aafb0058a5..6e111745627f7 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -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; + } } diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java new file mode 100644 index 0000000000000..21ccff707d347 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java @@ -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(); +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.java new file mode 100644 index 0000000000000..1d51e5925de89 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.java @@ -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); + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java new file mode 100644 index 0000000000000..880822aa7343e --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java @@ -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 {} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java index 6214a6448287a..33407918f9382 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java @@ -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 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()); diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java index c9164f0c4459f..9d8e73a0ff472 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/dagger/KeyguardModule.java @@ -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 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index d83758a574011..fc7e548e3f41a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -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 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 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 diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java index d278905abacb0..eb8f065149c83 100644 --- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java +++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java @@ -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. */ diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java index 657e4fbb4633c..3aa6ec08683ff 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java @@ -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 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 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 listenerArgumentCaptor = ArgumentCaptor.forClass(ClockManager.ClockChangedListener.class); - mController.attach(mView); + mController.init(); verify(mClockManager).addOnClockChangedListener(listenerArgumentCaptor.capture()); listenerArgumentCaptor.getValue().onClockChanged(mClockPlugin); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java index 446b1228f1bb4..559284ac06728 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPresentationTest.java @@ -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 */); } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java new file mode 100644 index 0000000000000..b7bcaa3c35660 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java @@ -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 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)); + } +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java index 06552b9bdbb42..1ab08c27088ac 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java @@ -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)); - } } diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java index 0bf137689aa14..0431704778c3b 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardStatusViewTest.java @@ -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 diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java index c874b1fb72adc..f6d6f562e3fa0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java @@ -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(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index 04e870d4b35c8..a9484af66c129 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -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,