From cd42c08702ef6cc25b974521ef9376e3b0d48bf8 Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Fri, 31 Jul 2020 14:12:39 -0400 Subject: [PATCH 1/2] Add KeyguardSliceViewController. This removes view injection from KeyguardSliceView. It also creates a KeyguardStatusView Dagger Subcomponent should be initilialized whenever a KeyguardStatusView is inflated. From that subcomponent, KeyguardClockSwitchController and KeyguardSliceViewController can both be created and initialized, passing their related views into their constructor. This fixes a bug introduced earlier where a KeyguardClockSwitchController was not being created in one place where it was needed. Bug: 162525274 Test: atest SystemUITests Change-Id: Ie571cb0ca2b793c363e3c8ab397828f0ee939763 --- .../android/keyguard/KeyguardClockSwitch.java | 2 + .../KeyguardClockSwitchController.java | 26 ++- .../keyguard/KeyguardDisplayManager.java | 12 +- .../android/keyguard/KeyguardSliceView.java | 137 ++----------- .../keyguard/KeyguardSliceViewController.java | 184 ++++++++++++++++++ .../dagger/KeyguardStatusViewComponent.java | 39 ++++ .../dagger/KeyguardStatusViewModule.java | 39 ++++ .../dagger/KeyguardStatusViewScope.java | 32 +++ .../keyguard/KeyguardViewMediator.java | 13 +- .../keyguard/dagger/KeyguardModule.java | 10 +- .../NotificationPanelViewController.java | 22 ++- .../util/InjectionInflationController.java | 6 - .../KeyguardClockSwitchControllerTest.java | 31 +-- .../KeyguardSliceViewControllerTest.java | 97 +++++++++ .../keyguard/KeyguardSliceViewTest.java | 73 +------ .../keyguard/KeyguardViewMediatorTest.java | 6 +- .../phone/NotificationPanelViewTest.java | 15 +- 17 files changed, 508 insertions(+), 236 deletions(-) create mode 100644 packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java create mode 100644 packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewComponent.java create mode 100644 packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewModule.java create mode 100644 packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusViewScope.java create mode 100644 packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java 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..33985bcb8c495 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 */); @@ -138,6 +145,9 @@ public class KeyguardDisplayManager { presentation = null; } if (presentation != null) { + mKeyguardStatusViewComponentFactory + .build(presentation.findViewById(R.id.clock)) + .getKeyguardClockSwitchController().init(); mPresentations.append(displayId, presentation); return true; } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index f639c880c97ae..95a048baa3325 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -17,11 +17,8 @@ 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 +32,22 @@ 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,11 +55,9 @@ 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; @@ -77,24 +66,17 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import javax.inject.Inject; -import javax.inject.Named; - /** * 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 implements View.OnClickListener { 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 ActivityStarter mActivityStarter; private final LayoutTransition mLayoutTransition; - private final TunerService mTunerService; - private Uri mKeyguardSliceUri; @VisibleForTesting TextView mTitle; private Row mRow; @@ -109,25 +91,20 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe * 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 KeyguardSliceViewController mController; - @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; + Resources resources = context.getResources(); mClickActions = new HashMap<>(); 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); @@ -157,34 +134,6 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe 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,9 +147,9 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe return mHasHeader; } - private void showSlice() { + void showSlice(Slice slice) { Trace.beginSection("KeyguardSliceView#showSlice"); - if (mSlice == null) { + if (slice == null) { mTitle.setVisibility(GONE); mRow.setVisibility(GONE); mHasHeader = false; @@ -212,7 +161,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe } mClickActions.clear(); - ListContent lc = new ListContent(getContext(), mSlice); + ListContent lc = new ListContent(getContext(), slice); SliceContent headerContent = lc.getHeader(); mHasHeader = headerContent != null && !headerContent.getSliceItem().hasHint(HINT_LIST_ITEM); List subItems = new ArrayList<>(); @@ -326,7 +275,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe @Override public void onClick(View v) { final PendingIntent action = mClickActions.get(v); - if (action != null) { + if (action != null && mActivityStarter != null) { mActivityStarter.startPendingIntentDismissingKeyguard(action); } } @@ -339,43 +288,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 +299,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( @@ -398,23 +309,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe } 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(); + mController.refresh(); } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { @@ -424,10 +319,18 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe 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); } + public void setActivityStarter(ActivityStarter activityStarter) { + mActivityStarter = activityStarter; + } + + public void setController(KeyguardSliceViewController keyguardSliceViewController) { + // TODO: remove this method. + mController = keyguardSliceViewController; + } + 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..68fa0b010a3e6 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java @@ -0,0 +1,184 @@ +/* + * 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.view.Display.DEFAULT_DISPLAY; + +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.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 javax.inject.Inject; + +/** Controller for a {@link KeyguardSliceView}. */ +@KeyguardStatusViewScope +public class KeyguardSliceViewController implements Dumpable { + private static final String TAG = "KeyguardSliceViewController"; + + private final KeyguardSliceView mView; + 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 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; + mView.showSlice(slice); + } + }; + + @Inject + public KeyguardSliceViewController(KeyguardSliceView keyguardSliceView, + ActivityStarter activityStarter, ConfigurationController configurationController, + TunerService tunerService, DumpManager dumpManager) { + mView = keyguardSliceView; + mActivityStarter = activityStarter; + mConfigurationController = configurationController; + mTunerService = tunerService; + mDumpManager = dumpManager; + } + + /** Initialize the controller. */ + public void init() { + if (mView.isAttachedToWindow()) { + mOnAttachStateChangeListener.onViewAttachedToWindow(mView); + } + mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener); + mView.setActivityStarter(mActivityStarter); + mView.setController(this); // TODO: remove 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(); + } + + @Override + public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { + pw.println(" mSlice: " + mSlice); + } +} 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/KeyguardSliceViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java new file mode 100644 index 0000000000000..991d99588127b --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java @@ -0,0 +1,97 @@ +/* + * 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 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, mActivityStarter, mConfigurationController, mTunerService, mDumpManager); + mController.setupUri(KeyguardSliceProvider.KEYGUARD_SLICE_URI); + } + + + @Test + public void refresh_replacesSliceContentAndNotifiesListener() { + mController.refresh(); + verify(mView).showSlice(null); + } + + @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..f388ad02647d5 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java @@ -15,20 +15,12 @@ */ 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.SliceProvider; import androidx.slice.SliceSpecs; @@ -37,9 +29,6 @@ import androidx.slice.builders.ListBuilder; 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; @@ -53,46 +42,21 @@ 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; + private KeyguardSliceViewController mKeyguardSliceViewController; @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); + mKeyguardSliceView.setController(mKeyguardSliceViewController); mSliceUri = Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI); SliceProvider.setSpecs(new HashSet<>(Collections.singletonList(SliceSpecs.LIST))); } @@ -102,7 +66,7 @@ public class KeyguardSliceViewTest extends SysuiTestCase { ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY); AtomicBoolean notified = new AtomicBoolean(); mKeyguardSliceView.setContentChangeListener(()-> notified.set(true)); - mKeyguardSliceView.onChanged(builder.build()); + mKeyguardSliceView.showSlice(builder.build()); Assert.assertTrue("Listener should be notified about slice changes.", notified.get()); } @@ -111,7 +75,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); Assert.assertTrue("Listener should be notified about slice changes.", notified.get()); } @@ -119,23 +83,14 @@ public class KeyguardSliceViewTest extends SysuiTestCase { @Test public void hasHeader_readsSliceData() { ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY); - mKeyguardSliceView.onChanged(builder.build()); + mKeyguardSliceView.showSlice(builder.build()); Assert.assertFalse("View should not have a header", mKeyguardSliceView.hasHeader()); builder.setHeader(new ListBuilder.HeaderBuilder().setTitle("header title!")); - mKeyguardSliceView.onChanged(builder.build()); + mKeyguardSliceView.showSlice(builder.build()); 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 +102,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/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, From 93dd88388b075e21f7deae648c553335fd49805c Mon Sep 17 00:00:00 2001 From: Dave Mankoff Date: Mon, 3 Aug 2020 11:51:50 -0400 Subject: [PATCH 2/2] Remove ref to Controller from KeyguardSliceView This removes the reference that the view has to its controller, moving click handling up to the controller. Fixes: 162525274 Test: atest SystemUITEsts Change-Id: Ia99ff4e643fa84fa138720cc5c01c51597f1169d --- .../keyguard/KeyguardDisplayManager.java | 14 ++- .../android/keyguard/KeyguardSliceView.java | 91 +++++-------------- .../keyguard/KeyguardSliceViewController.java | 62 +++++++++++-- .../android/keyguard/KeyguardStatusView.java | 11 ++- .../keyguard/KeyguardPresentationTest.java | 16 +++- .../KeyguardSliceViewControllerTest.java | 10 +- .../keyguard/KeyguardSliceViewTest.java | 20 ++-- .../keyguard/KeyguardStatusViewTest.java | 5 +- 8 files changed, 135 insertions(+), 94 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java index 33985bcb8c495..be21d203411e3 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardDisplayManager.java @@ -131,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))) { @@ -145,9 +146,6 @@ public class KeyguardDisplayManager { presentation = null; } if (presentation != null) { - mKeyguardStatusViewComponentFactory - .build(presentation.findViewById(R.id.clock)) - .getKeyguardClockSwitchController().init(); mPresentations.append(displayId, presentation); return true; } @@ -251,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; @@ -269,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); @@ -312,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 95a048baa3325..a479bca56c2ac 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -16,9 +16,6 @@ package com.android.keyguard; -import static android.app.slice.Slice.HINT_LIST_ITEM; -import static android.view.Display.INVALID_DISPLAY; - import android.animation.LayoutTransition; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; @@ -41,11 +38,8 @@ import android.view.animation.Animation; import android.widget.LinearLayout; import android.widget.TextView; -import androidx.lifecycle.LiveData; -import androidx.slice.Slice; import androidx.slice.SliceItem; import androidx.slice.core.SliceQuery; -import androidx.slice.widget.ListContent; import androidx.slice.widget.RowContent; import androidx.slice.widget.SliceContent; @@ -55,27 +49,23 @@ import com.android.settingslib.Utils; import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.keyguard.KeyguardSliceProvider; -import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.statusbar.policy.ConfigurationController; 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 java.util.Map; /** * View visible under the clock on the lock screen and AoD. */ -public class KeyguardSliceView extends LinearLayout implements View.OnClickListener { +public class KeyguardSliceView extends LinearLayout { private static final String TAG = "KeyguardSliceView"; public static final int DEFAULT_ANIM_DURATION = 550; - private final HashMap mClickActions; - private ActivityStarter mActivityStarter; private final LayoutTransition mLayoutTransition; @VisibleForTesting TextView mTitle; @@ -83,8 +73,6 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe private int mTextColor; private float mDarkAmount = 0; - private LiveData mLiveData; - private int mDisplayId = INVALID_DISPLAY; private int mIconSize; private int mIconSizeWithHeader; /** @@ -96,13 +84,12 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe private final int mRowPadding; private float mRowTextSize; private float mRowWithHeaderTextSize; - private KeyguardSliceViewController mController; + private View.OnClickListener mOnClickListener; public KeyguardSliceView(Context context, AttributeSet attrs) { super(context, attrs); Resources resources = context.getResources(); - mClickActions = new HashMap<>(); mRowPadding = resources.getDimensionPixelSize(R.dimen.subtitle_clock_padding); mRowWithHeaderPadding = resources.getDimensionPixelSize(R.dimen.header_subtitle_padding); @@ -130,7 +117,6 @@ 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); } @@ -147,44 +133,31 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe return mHasHeader; } - void showSlice(Slice slice) { - Trace.beginSection("KeyguardSliceView#showSlice"); - if (slice == 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(), slice); - 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()); } } @@ -214,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()); @@ -235,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--; } @@ -252,6 +225,8 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe mContentChangeListener.run(); } Trace.endSection(); + + return clickActions; } public void setDarkAmount(float darkAmount) { @@ -272,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 != null) { - mActivityStarter.startPendingIntentDismissingKeyguard(action); - } - } - /** * Runnable that gets invoked every time the title or the row visibility changes. * @param contentChangeListener The listener. @@ -308,13 +275,8 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe R.dimen.header_row_font_size); } - public void refresh() { - mController.refresh(); - } - 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)); @@ -322,13 +284,10 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe pw.println(" mHasHeader: " + mHasHeader); } - public void setActivityStarter(ActivityStarter activityStarter) { - mActivityStarter = activityStarter; - } - - public void setController(KeyguardSliceViewController keyguardSliceViewController) { - // TODO: remove this method. - mController = keyguardSliceViewController; + @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 index 68fa0b010a3e6..35a2392ba1cf8 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceViewController.java @@ -16,8 +16,10 @@ 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; @@ -30,6 +32,9 @@ 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; @@ -42,15 +47,19 @@ 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 = "KeyguardSliceViewController"; + 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; @@ -59,6 +68,7 @@ public class KeyguardSliceViewController implements Dumpable { private LiveData mLiveData; private Uri mKeyguardSliceUri; private Slice mSlice; + private Map mClickActions; private final View.OnAttachStateChangeListener mOnAttachStateChangeListener = new View.OnAttachStateChangeListener() { @@ -106,15 +116,27 @@ public class KeyguardSliceViewController implements Dumpable { @Override public void onChanged(Slice slice) { mSlice = slice; - mView.showSlice(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, - ActivityStarter activityStarter, ConfigurationController configurationController, - TunerService tunerService, DumpManager dumpManager) { + KeyguardStatusView keyguardStatusView, ActivityStarter activityStarter, + ConfigurationController configurationController, TunerService tunerService, + DumpManager dumpManager) { mView = keyguardSliceView; + mKeyguardStatusView = keyguardStatusView; mActivityStarter = activityStarter; mConfigurationController = configurationController; mTunerService = tunerService; @@ -127,8 +149,9 @@ public class KeyguardSliceViewController implements Dumpable { mOnAttachStateChangeListener.onViewAttachedToWindow(mView); } mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener); - mView.setActivityStarter(mActivityStarter); - mView.setController(this); // TODO: remove this. + mView.setOnClickListener(mOnClickListener); + // TODO: remove the line below. + mKeyguardStatusView.setKeyguardSliceViewController(this); } /** @@ -177,8 +200,35 @@ public class KeyguardSliceViewController implements Dumpable { 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/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 index 991d99588127b..b7bcaa3c35660 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewControllerTest.java @@ -44,7 +44,9 @@ import org.mockito.MockitoAnnotations; @RunWithLooper(setAsMainLooper = true) public class KeyguardSliceViewControllerTest extends SysuiTestCase { @Mock - private KeyguardSliceView mView; + private KeyguardSliceView mView;; + @Mock + private KeyguardStatusView mKeyguardStatusView; @Mock private TunerService mTunerService; @Mock @@ -61,15 +63,15 @@ public class KeyguardSliceViewControllerTest extends SysuiTestCase { when(mView.isAttachedToWindow()).thenReturn(true); when(mView.getContext()).thenReturn(mContext); mController = new KeyguardSliceViewController( - mView, mActivityStarter, mConfigurationController, mTunerService, mDumpManager); + mView, mKeyguardStatusView, mActivityStarter, mConfigurationController, + mTunerService, mDumpManager); mController.setupUri(KeyguardSliceProvider.KEYGUARD_SLICE_URI); } - @Test public void refresh_replacesSliceContentAndNotifiesListener() { mController.refresh(); - verify(mView).showSlice(null); + verify(mView).hideSlice(); } @Test diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java index f388ad02647d5..1ab08c27088ac 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java @@ -22,9 +22,11 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper.RunWithLooper; import android.view.LayoutInflater; +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; @@ -34,7 +36,6 @@ 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; @@ -47,8 +48,6 @@ import java.util.concurrent.atomic.AtomicBoolean; public class KeyguardSliceViewTest extends SysuiTestCase { private KeyguardSliceView mKeyguardSliceView; private Uri mSliceUri; - @Mock - private KeyguardSliceViewController mKeyguardSliceViewController; @Before public void setUp() throws Exception { @@ -56,7 +55,6 @@ public class KeyguardSliceViewTest extends SysuiTestCase { LayoutInflater layoutInflater = LayoutInflater.from(getContext()); mKeyguardSliceView = (KeyguardSliceView) layoutInflater .inflate(R.layout.keyguard_status_area, null); - mKeyguardSliceView.setController(mKeyguardSliceViewController); mSliceUri = Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI); SliceProvider.setSpecs(new HashSet<>(Collections.singletonList(SliceSpecs.LIST))); } @@ -64,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.showSlice(builder.build()); + mKeyguardSliceView.showSlice(rowContent, Collections.EMPTY_LIST); Assert.assertTrue("Listener should be notified about slice changes.", notified.get()); } @@ -75,7 +77,7 @@ public class KeyguardSliceViewTest extends SysuiTestCase { public void showSlice_emptySliceNotifiesListener() { AtomicBoolean notified = new AtomicBoolean(); mKeyguardSliceView.setContentChangeListener(()-> notified.set(true)); - mKeyguardSliceView.showSlice(null); + mKeyguardSliceView.showSlice(null, Collections.EMPTY_LIST); Assert.assertTrue("Listener should be notified about slice changes.", notified.get()); } @@ -83,11 +85,13 @@ public class KeyguardSliceViewTest extends SysuiTestCase { @Test public void hasHeader_readsSliceData() { ListBuilder builder = new ListBuilder(getContext(), mSliceUri, ListBuilder.INFINITY); - mKeyguardSliceView.showSlice(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.showSlice(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()); } 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