Merge "Remove communal support from SystemUI." into tm-dev

This commit is contained in:
Bryce Lee
2022-03-04 22:50:50 +00:00
committed by Android (Google) Code Review
35 changed files with 19 additions and 2970 deletions

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 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.
-->
<!-- This is a view that shows general status information in Keyguard. -->
<com.android.systemui.communal.CommunalHostView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/communal_host"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

View File

@@ -26,9 +26,6 @@
android:layout_height="match_parent"
android:background="@android:color/transparent">
<include layout="@layout/communal_host_view"
android:visibility="gone"/>
<ViewStub
android:id="@+id/keyguard_qs_user_switch_stub"
android:layout="@layout/keyguard_qs_user_switch"

View File

@@ -20,7 +20,6 @@ import android.graphics.Rect;
import android.util.Slog;
import com.android.keyguard.KeyguardClockSwitch.ClockSize;
import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
@@ -63,7 +62,6 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
KeyguardClockSwitchController keyguardClockSwitchController,
KeyguardStateController keyguardStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
CommunalStateController communalStateController,
ConfigurationController configurationController,
DozeParameters dozeParameters,
KeyguardUnlockAnimationController keyguardUnlockAnimationController,
@@ -75,9 +73,8 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
mConfigurationController = configurationController;
mDozeParameters = dozeParameters;
mKeyguardStateController = keyguardStateController;
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, communalStateController,
keyguardStateController, dozeParameters, screenOffAnimationController,
/* animateYPos= */ true, /* visibleOnCommunal= */ false);
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, keyguardStateController,
dozeParameters, screenOffAnimationController, /* animateYPos= */ true);
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
}

View File

@@ -22,7 +22,6 @@ import android.view.View;
import android.view.ViewPropertyAnimator;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
@@ -39,30 +38,24 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
public class KeyguardVisibilityHelper {
private View mView;
private final CommunalStateController mCommunalStateController;
private final KeyguardStateController mKeyguardStateController;
private final DozeParameters mDozeParameters;
private final ScreenOffAnimationController mScreenOffAnimationController;
private final boolean mVisibleOnCommunal;
private boolean mAnimateYPos;
private boolean mKeyguardViewVisibilityAnimating;
private boolean mLastOccludedState = false;
private final AnimationProperties mAnimationProperties = new AnimationProperties();
public KeyguardVisibilityHelper(View view,
CommunalStateController communalStateController,
KeyguardStateController keyguardStateController,
DozeParameters dozeParameters,
ScreenOffAnimationController screenOffAnimationController,
boolean animateYPos,
boolean visibleOnCommunal) {
boolean animateYPos) {
mView = view;
mCommunalStateController = communalStateController;
mKeyguardStateController = keyguardStateController;
mDozeParameters = dozeParameters;
mScreenOffAnimationController = screenOffAnimationController;
mAnimateYPos = animateYPos;
mVisibleOnCommunal = visibleOnCommunal;
}
public boolean isVisibilityAnimating() {
@@ -81,13 +74,6 @@ public class KeyguardVisibilityHelper {
boolean isOccluded = mKeyguardStateController.isOccluded();
mKeyguardViewVisibilityAnimating = false;
// If the communal view is showing, hide immediately
if (!mVisibleOnCommunal && mCommunalStateController.getCommunalViewShowing()) {
mView.setVisibility(View.GONE);
mView.setAlpha(1f);
return;
}
if ((!keyguardFadingAway && oldStatusBarState == KEYGUARD
&& statusBarState != KEYGUARD) || goingToFullShade) {
mKeyguardViewVisibilityAnimating = true;

View File

@@ -1,45 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* Container for communal presentation. Containing communal-related view to this parent view allows
* for aggregate measurement/layout adjustments and capturing said values before the communal views
* might be available.
*/
public class CommunalHostView extends FrameLayout {
public CommunalHostView(@NonNull Context context) {
this(context, null, 0);
}
public CommunalHostView(@NonNull Context context,
@Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CommunalHostView(@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}

View File

@@ -1,396 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal;
import android.annotation.IntDef;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.KeyguardVisibilityHelper;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.PropertyAnimator;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.ViewController;
import com.google.common.util.concurrent.ListenableFuture;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.Executor;
import javax.inject.Inject;
/**
* Injectable controller for {@link CommunalHostView}.
*/
public class CommunalHostViewController extends ViewController<CommunalHostView> {
private static final String TAG = "CommunalController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final String STATE_LIST_FORMAT = "[%s]";
private static final AnimationProperties COMMUNAL_ANIMATION_PROPERTIES =
new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
private final Executor mMainExecutor;
private final CommunalStateController mCommunalStateController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
private final KeyguardStateController mKeyguardStateController;
private final StatusBarStateController mStatusBarStateController;
private WeakReference<CommunalSource> mCurrentSource;
private Optional<ShowRequest> mLastRequest = Optional.empty();
private int mState;
private float mQsExpansion;
private float mShadeExpansion;
@Retention(RetentionPolicy.RUNTIME)
@IntDef({STATE_KEYGUARD_SHOWING, STATE_DOZING, STATE_BOUNCER_SHOWING, STATE_KEYGUARD_OCCLUDED})
public @interface State {}
private static final int STATE_KEYGUARD_SHOWING = 1 << 0;
private static final int STATE_DOZING = 1 << 1;
private static final int STATE_BOUNCER_SHOWING = 1 << 2;
private static final int STATE_KEYGUARD_OCCLUDED = 1 << 3;
// Only show communal view when keyguard is showing and not dozing.
private static final int SHOW_COMMUNAL_VIEW_REQUIRED_STATES = STATE_KEYGUARD_SHOWING;
private static final int SHOW_COMMUNAL_VIEW_INVALID_STATES =
STATE_DOZING | STATE_KEYGUARD_OCCLUDED;
private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
private ViewController<? extends View> mCommunalViewController;
private static class ShowRequest {
private boolean mShouldShow;
private WeakReference<CommunalSource> mSource;
ShowRequest(boolean shouldShow, WeakReference<CommunalSource> source) {
mShouldShow = shouldShow;
mSource = source;
}
CommunalSource getSource() {
return mSource != null ? mSource.get() : null;
}
boolean shouldShow() {
return mShouldShow;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ShowRequest)) return false;
ShowRequest that = (ShowRequest) o;
return mShouldShow == that.mShouldShow && Objects.equals(getSource(), that.getSource());
}
@Override
public int hashCode() {
return Objects.hash(mShouldShow, mSource);
}
}
private KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
new KeyguardUpdateMonitorCallback() {
@Override
public void onKeyguardBouncerChanged(boolean bouncer) {
if (DEBUG) {
Log.d(TAG, "onKeyguardBouncerChanged:" + bouncer);
}
setState(STATE_BOUNCER_SHOWING, bouncer);
}
@Override
public void onKeyguardOccludedChanged(boolean occluded) {
if (DEBUG) {
Log.d(TAG, "onKeyguardOccludedChanged" + occluded);
}
setState(STATE_KEYGUARD_OCCLUDED, occluded);
}
};
private KeyguardStateController.Callback mKeyguardCallback =
new KeyguardStateController.Callback() {
@Override
public void onKeyguardShowingChanged() {
final boolean isShowing = mKeyguardStateController.isShowing();
if (DEBUG) {
Log.d(TAG, "setKeyguardShowing:" + isShowing);
}
setState(STATE_KEYGUARD_SHOWING, isShowing);
}
};
private StatusBarStateController.StateListener mDozeCallback =
new StatusBarStateController.StateListener() {
@Override
public void onDozingChanged(boolean isDozing) {
if (DEBUG) {
Log.d(TAG, "setDozing:" + isDozing);
}
setState(STATE_DOZING, isDozing);
}
@Override
public void onStateChanged(int newState) {
updateCommunalViewOccluded();
}
};
@Inject
protected CommunalHostViewController(@Main Executor mainExecutor,
CommunalStateController communalStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
KeyguardStateController keyguardStateController,
DozeParameters dozeParameters,
ScreenOffAnimationController screenOffAnimationController,
StatusBarStateController statusBarStateController, CommunalHostView view) {
super(view);
mCommunalStateController = communalStateController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mMainExecutor = mainExecutor;
mKeyguardStateController = keyguardStateController;
mStatusBarStateController = statusBarStateController;
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, communalStateController,
keyguardStateController, dozeParameters, screenOffAnimationController,
/* animateYPos= */ false, /* visibleOnCommunal= */ true);
}
/**
* Set the visibility of the keyguard status view based on some new state.
*/
public void setKeyguardStatusViewVisibility(
int statusBarState,
boolean keyguardFadingAway,
boolean goingToFullShade,
int oldStatusBarState) {
mKeyguardVisibilityHelper.setViewVisibility(
statusBarState, keyguardFadingAway, goingToFullShade, oldStatusBarState);
}
/**
* Set keyguard status view alpha.
*/
public void setAlpha(float alpha) {
if (!mKeyguardVisibilityHelper.isVisibilityAnimating()) {
mView.setAlpha(alpha);
// Some communal view implementations, such as SurfaceViews, do not behave correctly
// inheriting the alpha of their parent. Directly set child alpha here to work around
// this.
for (int i = mView.getChildCount() - 1; i >= 0; --i) {
mView.getChildAt(i).setAlpha(alpha);
}
}
}
@Override
public void onInit() {
setState(STATE_KEYGUARD_SHOWING, mKeyguardStateController.isShowing());
setState(STATE_DOZING, mStatusBarStateController.isDozing());
}
@Override
protected void onViewAttached() {
mKeyguardStateController.addCallback(mKeyguardCallback);
mStatusBarStateController.addCallback(mDozeCallback);
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
}
@Override
protected void onViewDetached() {
mKeyguardStateController.removeCallback(mKeyguardCallback);
mStatusBarStateController.removeCallback(mDozeCallback);
mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
}
private void setState(@State int stateFlag, boolean enabled) {
final int existingState = mState;
if (DEBUG) {
Log.d(TAG, "setState flag:" + describeState(stateFlag) + " enabled:" + enabled);
}
if (enabled) {
mState |= stateFlag;
} else {
mState &= ~stateFlag;
}
if (DEBUG) {
Log.d(TAG, "updated state:" + describeState());
}
if (existingState != mState) {
showSource();
}
updateCommunalViewOccluded();
}
private String describeState(@State int stateFlag) {
switch(stateFlag) {
case STATE_DOZING:
return "dozing";
case STATE_BOUNCER_SHOWING:
return "bouncer_showing";
case STATE_KEYGUARD_SHOWING:
return "keyguard_showing";
default:
return "UNDEFINED_STATE";
}
}
private String describeState() {
StringBuilder stringBuilder = new StringBuilder();
if ((mState & STATE_KEYGUARD_SHOWING) == STATE_KEYGUARD_SHOWING) {
stringBuilder.append(String.format(STATE_LIST_FORMAT,
describeState(STATE_KEYGUARD_SHOWING)));
}
if ((mState & STATE_DOZING) == STATE_DOZING) {
stringBuilder.append(String.format(STATE_LIST_FORMAT,
describeState(STATE_DOZING)));
}
if ((mState & STATE_BOUNCER_SHOWING) == STATE_BOUNCER_SHOWING) {
stringBuilder.append(String.format(STATE_LIST_FORMAT,
describeState(STATE_BOUNCER_SHOWING)));
}
return stringBuilder.toString();
}
private void showSource() {
final ShowRequest request = new ShowRequest(
(mState & SHOW_COMMUNAL_VIEW_REQUIRED_STATES) == SHOW_COMMUNAL_VIEW_REQUIRED_STATES
&& (mState & SHOW_COMMUNAL_VIEW_INVALID_STATES) == 0
&& mCurrentSource != null,
mCurrentSource);
if (mLastRequest.isPresent() && Objects.equals(mLastRequest.get(), request)) {
return;
}
mLastRequest = Optional.of(request);
// Make sure all necessary states are present for showing communal and all invalid states
// are absent
mMainExecutor.execute(() -> {
if (DEBUG) {
Log.d(TAG, "showSource. currentSource:" + request.getSource());
}
if (request.shouldShow()) {
mView.removeAllViews();
// Make view visible.
mView.setVisibility(View.VISIBLE);
final Context context = mView.getContext();
final ListenableFuture<CommunalSource.CommunalViewResult> listenableFuture =
request.getSource().requestCommunalView(context);
if (listenableFuture == null) {
Log.e(TAG, "could not request communal view");
return;
}
listenableFuture.addListener(() -> {
try {
final CommunalSource.CommunalViewResult result = listenableFuture.get();
result.view.setLayoutParams(new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
mView.addView(result.view);
mCommunalViewController = result.viewController;
mCommunalViewController.init();
} catch (Exception e) {
Log.e(TAG, "could not obtain communal view through callback:" + e);
}
}, mMainExecutor);
} else {
mView.removeAllViews();
mView.setVisibility(View.INVISIBLE);
mCommunalStateController.setCommunalViewShowing(false);
}
});
}
/**
* Instructs {@link CommunalHostViewController} to display provided source.
*
* @param source The new {@link CommunalSource}, {@code null} if not set.
*/
public void show(WeakReference<CommunalSource> source) {
mCurrentSource = source;
showSource();
}
/**
* Update position of the view with an optional animation
*/
public void updatePosition(int y, boolean animate) {
PropertyAnimator.setProperty(mView, AnimatableProperty.Y, y, COMMUNAL_ANIMATION_PROPERTIES,
animate);
}
/**
* Invoked when the quick settings is expanded.
* @param expansionFraction the percentage the QS shade has been expanded.
*/
public void updateQsExpansion(float expansionFraction) {
mQsExpansion = expansionFraction;
updateCommunalViewOccluded();
}
/**
* Invoked when the main shade is expanded.
* @param shadeExpansion the percentage the main shade has expanded.
*/
public void updateShadeExpansion(float shadeExpansion) {
mShadeExpansion = shadeExpansion;
updateCommunalViewOccluded();
}
private void updateCommunalViewOccluded() {
final boolean bouncerShowing = (mState & STATE_BOUNCER_SHOWING) == STATE_BOUNCER_SHOWING;
final int statusBarState = mStatusBarStateController.getState();
final boolean shadeExpanded = statusBarState == StatusBarState.SHADE
|| statusBarState == StatusBarState.SHADE_LOCKED;
mCommunalStateController.setCommunalViewOccluded(
bouncerShowing || shadeExpanded || mQsExpansion > 0.0f || mShadeExpansion > 0.0f);
}
}

View File

@@ -1,74 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal;
import android.util.Log;
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
/**
* {@link CommunalHostViewPositionAlgorithm} calculates the position of the communal view given
* input such as the notification panel position.
*/
public class CommunalHostViewPositionAlgorithm {
private static final String TAG = "CommunalPositionAlg";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
/**
* @see NotificationPanelViewController#getExpandedFraction()
*/
private float mPanelExpansion;
/**
* Height of {@link CommunalHostView}.
*/
private int mCommunalHeight;
/**
* A data container for the result of the position algorithm.
*/
public static class Result {
/**
* The y translation of the clock.
*/
public int communalY;
}
/**
* Sets the conditions under which the result should be calculated from.
* @param panelExpansion The percentage the keyguard panel has been moved upwards.
* @param communalHeight The height of the communal panel.
*/
public void setup(float panelExpansion, int communalHeight) {
if (DEBUG) {
Log.d(TAG, "setup. panelExpansion:" + panelExpansion);
}
mPanelExpansion = panelExpansion;
mCommunalHeight = communalHeight;
}
/**
* Calculates the position based on factors input through {link {@link #setup(float, int)}}.
* @param result The resulting calculations.
*/
public void run(Result result) {
// The panel expansion relates to the keyguard expansion. At full expansion, the communal
// view should be aligned at the top (0). Otherwise, it should be shifted offscreen by the
// unexpanded amount.
result.communalY = (int) ((1 - mPanelExpansion) * -mCommunalHeight);
}
}

View File

@@ -1,105 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal;
import android.content.Context;
import android.view.View;
import com.android.systemui.util.ViewController;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.Optional;
/**
* {@link CommunalSource} defines an interface for working with a source for communal data. Clients
* may request a communal surface that can be shown within a {@link android.view.SurfaceView}.
* Callbacks may also be registered to listen to state changes.
*/
public interface CommunalSource {
/**
* {@link Connector} defines an interface for {@link CommunalSource} instances to be generated.
*/
interface Connector {
Connection connect(Connection.Callback callback);
}
/**
* {@link Connection} defines an interface for an entity which holds the necessary components
* for establishing and maintaining a connection to the communal source.
*/
interface Connection {
/**
* {@link Callback} defines an interface for clients to be notified when a source is ready
*/
interface Callback {
void onSourceEstablished(Optional<CommunalSource> source);
void onDisconnected();
}
void disconnect();
}
/**
* The {@link Observer} interface specifies an entity which {@link CommunalSource} listeners
* can be informed of changes to the source, which will require updating. Note that this deals
* with changes to the source itself, not content which will be updated through the
* {@link CommunalSource} interface.
*/
interface Observer {
interface Callback {
void onSourceChanged();
}
void addCallback(Callback callback);
void removeCallback(Callback callback);
}
/**
* {@link CommunalViewResult} is handed back from {@link #requestCommunalView(Context)} and
* contains the view to be displayed and its associated controller.
*/
class CommunalViewResult {
/**
* The resulting communal view.
*/
public final View view;
/**
* The controller for the communal view.
*/
public final ViewController<? extends View> viewController;
/**
* The default constructor for {@link CommunalViewResult}.
* @param view The communal view.
* @param viewController The communal view's controller.
*/
public CommunalViewResult(View view, ViewController<? extends View> viewController) {
this.view = view;
this.viewController = viewController;
}
}
/**
* Requests a communal surface that can be displayed inside {@link CommunalHostView}.
*
* @param context The {@link View} {@link Context} to build the resulting view from
* @return A future that can be listened upon for the resulting {@link CommunalViewResult}. The
* value will be {@code null} in case of a failure.
*/
ListenableFuture<CommunalViewResult> requestCommunalView(Context context);
}

View File

@@ -1,158 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal;
import static com.android.systemui.communal.dagger.CommunalModule.COMMUNAL_CONDITIONS;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.condition.Monitor;
import com.google.android.collect.Lists;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Named;
/**
* A Monitor for reporting a {@link CommunalSource} presence.
*/
@SysUISingleton
public class CommunalSourceMonitor {
private static final String TAG = "CommunalSourceMonitor";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
// A list of {@link Callback} that have registered to receive updates.
private final ArrayList<WeakReference<Callback>> mCallbacks = Lists.newArrayList();
private final Monitor mConditionsMonitor;
private final Executor mExecutor;
private CommunalSource mCurrentSource;
// Whether all conditions for communal mode to show have been met.
private boolean mAllCommunalConditionsMet = false;
// Whether the class is currently listening for condition changes.
private boolean mListeningForConditions = false;
private final Monitor.Callback mConditionsCallback =
allConditionsMet -> {
if (mAllCommunalConditionsMet != allConditionsMet) {
if (DEBUG) Log.d(TAG, "communal conditions changed: " + allConditionsMet);
mAllCommunalConditionsMet = allConditionsMet;
executeOnSourceAvailableCallbacks();
}
};
@VisibleForTesting
@Inject
public CommunalSourceMonitor(@Main Executor executor,
@Named(COMMUNAL_CONDITIONS) Monitor communalConditionsMonitor) {
mExecutor = executor;
mConditionsMonitor = communalConditionsMonitor;
}
/**
* Sets the current {@link CommunalSource}, informing any callbacks. Any existing
* {@link CommunalSource} will be disconnected.
*
* @param source The new {@link CommunalSource}.
*/
public void setSource(CommunalSource source) {
mCurrentSource = source;
if (mAllCommunalConditionsMet) {
executeOnSourceAvailableCallbacks();
}
}
private void executeOnSourceAvailableCallbacks() {
mExecutor.execute(() -> {
// If the new source is valid, inform registered Callbacks of its presence.
Iterator<WeakReference<Callback>> itr = mCallbacks.iterator();
while (itr.hasNext()) {
Callback cb = itr.next().get();
if (cb == null) {
itr.remove();
} else {
cb.onSourceAvailable(
(mAllCommunalConditionsMet && mCurrentSource != null)
? new WeakReference<>(mCurrentSource) : null);
}
}
});
}
/**
* Adds a {@link Callback} to receive {@link CommunalSource} updates.
*
* @param callback The {@link Callback} to add.
*/
public void addCallback(Callback callback) {
mExecutor.execute(() -> {
mCallbacks.add(new WeakReference<>(callback));
// Inform the callback of any already present CommunalSource.
if (mAllCommunalConditionsMet && mCurrentSource != null) {
callback.onSourceAvailable(new WeakReference<>(mCurrentSource));
}
if (!mListeningForConditions) {
mConditionsMonitor.addCallback(mConditionsCallback);
mListeningForConditions = true;
}
});
}
/**
* Removes the specified {@link Callback} from receive future updates if present.
*
* @param callback The {@link Callback} to add.
*/
public void removeCallback(Callback callback) {
mExecutor.execute(() -> {
mCallbacks.removeIf(el -> el.get() == callback);
if (mCallbacks.isEmpty() && mListeningForConditions) {
mConditionsMonitor.removeCallback(mConditionsCallback);
mListeningForConditions = false;
}
});
}
/**
* Interface implemented to be notified when new {@link CommunalSource} become available.
*/
public interface Callback {
/**
* Called when a new {@link CommunalSource} has been registered. This will also be invoked
* when a {@link Callback} is first registered and a {@link CommunalSource} is already
* registered.
*
* @param source The new {@link CommunalSource}.
*/
void onSourceAvailable(WeakReference<CommunalSource> source);
}
}

View File

@@ -1,180 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal;
import android.content.Context;
import android.content.res.Resources;
import android.util.Log;
import com.android.systemui.CoreStartable;
import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.time.SystemClock;
import java.util.Optional;
import javax.inject.Inject;
/**
* The {@link CommunalSourcePrimer} is responsible for priming SystemUI with a pre-configured
* Communal source. The SystemUI service binds to the component to retrieve the
* {@link CommunalSource}. {@link CommunalSourcePrimer} has no effect
* if there is no pre-defined value.
*/
@SysUISingleton
public class CommunalSourcePrimer extends CoreStartable {
private static final String TAG = "CommunalSourcePrimer";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final SystemClock mSystemClock;
private final DelayableExecutor mMainExecutor;
private final CommunalSourceMonitor mMonitor;
private final int mBaseReconnectDelayMs;
private final int mMaxReconnectAttempts;
private final int mMinConnectionDuration;
private int mReconnectAttempts = 0;
private Runnable mCurrentReconnectCancelable;
private final Optional<CommunalSource.Observer> mObserver;
private final Optional<CommunalSource.Connector> mConnector;
private CommunalSource.Connection mCurrentConnection;
private final Runnable mConnectRunnable = new Runnable() {
@Override
public void run() {
mCurrentReconnectCancelable = null;
connect();
}
};
private final CommunalSource.Observer.Callback mObserverCallback = () -> {
initiateConnectionAttempt();
};
@Inject
public CommunalSourcePrimer(Context context, @Main Resources resources,
SystemClock clock,
DelayableExecutor mainExecutor,
CommunalSourceMonitor monitor,
Optional<CommunalSource.Connector> connector,
Optional<CommunalSource.Observer> observer) {
super(context);
mSystemClock = clock;
mMainExecutor = mainExecutor;
mMonitor = monitor;
mConnector = connector;
mObserver = observer;
mMaxReconnectAttempts = resources.getInteger(
R.integer.config_communalSourceMaxReconnectAttempts);
mBaseReconnectDelayMs = resources.getInteger(
R.integer.config_communalSourceReconnectBaseDelay);
mMinConnectionDuration = resources.getInteger(
R.integer.config_connectionMinDuration);
}
@Override
public void start() {
}
private void initiateConnectionAttempt() {
// Reset attempts
mReconnectAttempts = 0;
mMonitor.setSource(null);
// The first attempt is always a direct invocation rather than delayed.
connect();
}
private void scheduleConnectionAttempt() {
// always clear cancelable if present.
if (mCurrentReconnectCancelable != null) {
mCurrentReconnectCancelable.run();
mCurrentReconnectCancelable = null;
}
if (mReconnectAttempts >= mMaxReconnectAttempts) {
if (DEBUG) {
Log.d(TAG, "exceeded max connection attempts.");
}
return;
}
final long reconnectDelayMs =
(long) Math.scalb(mBaseReconnectDelayMs, mReconnectAttempts);
if (DEBUG) {
Log.d(TAG,
"scheduling connection attempt in " + reconnectDelayMs + "milliseconds");
}
mCurrentReconnectCancelable = mMainExecutor.executeDelayed(mConnectRunnable,
reconnectDelayMs);
mReconnectAttempts++;
}
@Override
protected void onBootCompleted() {
if (mObserver.isPresent()) {
mObserver.get().addCallback(mObserverCallback);
}
initiateConnectionAttempt();
}
private void connect() {
if (DEBUG) {
Log.d(TAG, "attempting to connect to communal source");
}
if (mCurrentConnection != null) {
if (DEBUG) {
Log.d(TAG, "canceling in-flight connection");
}
mCurrentConnection.disconnect();
}
mCurrentConnection = mConnector.get().connect(new CommunalSource.Connection.Callback() {
private long mStartTime;
@Override
public void onSourceEstablished(Optional<CommunalSource> optionalSource) {
mStartTime = mSystemClock.currentTimeMillis();
if (optionalSource.isPresent()) {
final CommunalSource source = optionalSource.get();
mMonitor.setSource(source);
} else {
scheduleConnectionAttempt();
}
}
@Override
public void onDisconnected() {
if (mSystemClock.currentTimeMillis() - mStartTime > mMinConnectionDuration) {
initiateConnectionAttempt();
} else {
scheduleConnectionAttempt();
}
}
});
}
}

View File

@@ -1,125 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal;
import android.annotation.NonNull;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.statusbar.policy.CallbackController;
import java.util.ArrayList;
import java.util.Objects;
import javax.inject.Inject;
/**
* CommunalStateController enables publishing and listening to communal-related state changes.
*/
@SysUISingleton
public class CommunalStateController implements
CallbackController<CommunalStateController.Callback> {
private final ArrayList<Callback> mCallbacks = new ArrayList<>();
private boolean mCommunalViewOccluded;
private boolean mCommunalViewShowing;
/**
* Callback for communal events.
*/
public interface Callback {
/**
* Called when the visibility of the communal view changes.
*/
default void onCommunalViewShowingChanged() {
}
/**
* Called when the occlusion of the communal view changes.
*/
default void onCommunalViewOccludedChanged() {
}
}
@VisibleForTesting
@Inject
public CommunalStateController() {
}
/**
* Sets whether the communal view is showing.
* @param communalViewShowing {@code true} if the view is showing, {@code false} otherwise.
*/
public void setCommunalViewShowing(boolean communalViewShowing) {
if (mCommunalViewShowing == communalViewShowing) {
return;
}
mCommunalViewShowing = communalViewShowing;
final ArrayList<Callback> callbacks = new ArrayList<>(mCallbacks);
for (Callback callback : callbacks) {
callback.onCommunalViewShowingChanged();
}
}
/**
* Sets whether the communal view is occluded (but otherwise still showing).
* @param communalViewOccluded {@code true} if the view is occluded, {@code false} otherwise.
*/
public void setCommunalViewOccluded(boolean communalViewOccluded) {
if (mCommunalViewOccluded == communalViewOccluded) {
return;
}
mCommunalViewOccluded = communalViewOccluded;
ArrayList<Callback> callbacks = new ArrayList<>(mCallbacks);
for (int i = 0; i < callbacks.size(); i++) {
callbacks.get(i).onCommunalViewOccludedChanged();
}
}
/**
* Returns whether the communal view is showing.
* @return {@code true} if the view is showing, {@code false} otherwise.
*/
public boolean getCommunalViewShowing() {
return mCommunalViewShowing;
}
/**
* Returns whether the communal view is occluded.
* @return {@code true} if the view is occluded, {@code false} otherwise.
*/
public boolean getCommunalViewOccluded() {
return mCommunalViewOccluded;
}
@Override
public void addCallback(@NonNull Callback callback) {
Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
if (!mCallbacks.contains(callback)) {
mCallbacks.add(callback);
}
}
@Override
public void removeCallback(@NonNull Callback callback) {
Objects.requireNonNull(callback, "Callback must not be null. b/128895449");
mCallbacks.remove(callback);
}
}

View File

@@ -1,101 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.PatternMatcher;
import android.util.Log;
import com.google.android.collect.Lists;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
/**
* {@link PackageObserver} allows for monitoring the system for changes relating to a particular
* package. This can be used by {@link CommunalSource} clients to detect when a related package
* has changed and reloading is necessary.
*/
public class PackageObserver implements CommunalSource.Observer {
private static final String TAG = "PackageObserver";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final ArrayList<WeakReference<Callback>> mCallbacks = Lists.newArrayList();
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) {
Log.d(TAG, "package added receiver - onReceive");
}
final Iterator<WeakReference<Callback>> iter = mCallbacks.iterator();
while (iter.hasNext()) {
final Callback callback = iter.next().get();
if (callback != null) {
callback.onSourceChanged();
} else {
iter.remove();
}
}
}
};
private final String mPackageName;
private final Context mContext;
public PackageObserver(Context context, String packageName) {
mContext = context;
mPackageName = packageName;
}
@Override
public void addCallback(Callback callback) {
if (DEBUG) {
Log.d(TAG, "addCallback:" + callback);
}
mCallbacks.add(new WeakReference<>(callback));
// Only register for listening to package additions on first callback.
if (mCallbacks.size() > 1) {
return;
}
final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addDataScheme("package");
filter.addDataSchemeSpecificPart(mPackageName, PatternMatcher.PATTERN_LITERAL);
// Note that we directly register the receiver here as data schemes are not supported by
// BroadcastDispatcher.
mContext.registerReceiver(mReceiver, filter, Context.RECEIVER_EXPORTED);
}
@Override
public void removeCallback(Callback callback) {
if (DEBUG) {
Log.d(TAG, "removeCallback:" + callback);
}
final boolean removed = mCallbacks.removeIf(el -> el.get() == callback);
if (removed && mCallbacks.isEmpty()) {
mContext.unregisterReceiver(mReceiver);
}
}
}

View File

@@ -1,67 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal.conditions;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import androidx.annotation.MainThread;
import com.android.systemui.util.condition.Condition;
import com.android.systemui.util.settings.SecureSettings;
import javax.inject.Inject;
/**
* Monitors the communal setting, and informs any listeners with updates.
*/
public class CommunalSettingCondition extends Condition {
private final SecureSettings mSecureSettings;
private final ContentObserver mCommunalSettingContentObserver;
@Inject
public CommunalSettingCondition(@MainThread Handler mainHandler,
SecureSettings secureSettings) {
mSecureSettings = secureSettings;
mCommunalSettingContentObserver = new ContentObserver(mainHandler) {
@Override
public void onChange(boolean selfChange) {
final boolean communalSettingEnabled = mSecureSettings.getIntForUser(
Settings.Secure.COMMUNAL_MODE_ENABLED, 0, UserHandle.USER_SYSTEM) == 1;
updateCondition(communalSettingEnabled);
}
};
}
@Override
protected void start() {
mSecureSettings.registerContentObserverForUser(Settings.Secure.COMMUNAL_MODE_ENABLED,
false /*notifyForDescendants*/, mCommunalSettingContentObserver,
UserHandle.USER_SYSTEM);
// Fetches setting immediately.
mCommunalSettingContentObserver.onChange(false);
}
@Override
protected void stop() {
mSecureSettings.unregisterContentObserver(mCommunalSettingContentObserver);
}
}

View File

@@ -1,125 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal.dagger;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import com.android.systemui.R;
import com.android.systemui.communal.CommunalSource;
import com.android.systemui.communal.PackageObserver;
import com.android.systemui.communal.conditions.CommunalSettingCondition;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.condition.Condition;
import com.android.systemui.util.condition.Monitor;
import com.android.systemui.util.condition.dagger.MonitorComponent;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.inject.Named;
import javax.inject.Provider;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.ElementsIntoSet;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
/**
* Dagger Module providing Communal-related functionality.
*/
@Module(subcomponents = {
CommunalViewComponent.class,
})
public interface CommunalModule {
String COMMUNAL_CONDITIONS = "communal_conditions";
/** */
@Provides
static Optional<CommunalSource.Observer> provideCommunalSourcePackageObserver(
Context context, @Main Resources resources) {
final String componentName = resources.getString(R.string.config_communalSourceComponent);
if (TextUtils.isEmpty(componentName)) {
return Optional.empty();
}
return Optional.of(new PackageObserver(context,
ComponentName.unflattenFromString(componentName).getPackageName()));
}
/**
* Provides a set of conditions that need to be fulfilled in order for Communal Mode to display.
*/
@Provides
@ElementsIntoSet
@Named(COMMUNAL_CONDITIONS)
static Set<Condition> provideCommunalConditions(
CommunalSettingCondition communalSettingCondition) {
return new HashSet<>(Collections.singletonList(communalSettingCondition));
}
/**
* TODO(b/205638389): Remove when there is a base implementation of
* {@link CommunalSource.Connector}. Currently a place holder to allow a map to be present.
*/
@Provides
@IntoMap
@Nullable
@StringKey("empty")
static CommunalSource.Connector provideEmptyCommunalSourceConnector() {
return null;
}
/** */
@Provides
static Optional<CommunalSource.Connector> provideCommunalSourceConnector(
@Main Resources resources,
Map<Class<?>, Provider<CommunalSource.Connector>> connectorCreators) {
final String className = resources.getString(R.string.config_communalSourceConnector);
if (TextUtils.isEmpty(className)) {
return Optional.empty();
}
try {
Class<?> clazz = Class.forName(className);
Provider<CommunalSource.Connector> provider = connectorCreators.get(clazz);
return provider != null ? Optional.of(provider.get()) : Optional.empty();
} catch (ClassNotFoundException e) {
return Optional.empty();
}
}
/** */
@Provides
@Named(COMMUNAL_CONDITIONS)
static Monitor provideCommunalSourceMonitor(
@Named(COMMUNAL_CONDITIONS) Set<Condition> communalConditions,
MonitorComponent.Factory factory) {
final MonitorComponent component = factory.create(communalConditions, new HashSet<>());
return component.getMonitor();
}
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal.dagger;
import com.android.systemui.communal.CommunalHostView;
import com.android.systemui.communal.CommunalHostViewController;
import dagger.BindsInstance;
import dagger.Subcomponent;
/**
* Subcomponent for working with {@link CommunalHostView}.
*/
@Subcomponent
public interface CommunalViewComponent {
/** Simple factory for {@link CommunalViewComponent}. */
@Subcomponent.Factory
interface Factory {
CommunalViewComponent build(@BindsInstance CommunalHostView view);
}
/** Builds a {@link CommunalHostViewController}. */
CommunalHostViewController getCommunalHostViewController();
}

View File

@@ -32,7 +32,6 @@ import com.android.systemui.assist.AssistModule;
import com.android.systemui.biometrics.UdfpsHbmProvider;
import com.android.systemui.biometrics.dagger.BiometricsModule;
import com.android.systemui.classifier.FalsingModule;
import com.android.systemui.communal.dagger.CommunalModule;
import com.android.systemui.controls.dagger.ControlsModule;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.demomode.dagger.DemoModeModule;
@@ -66,8 +65,8 @@ import com.android.systemui.statusbar.notification.people.PeopleHubModule;
import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -106,7 +105,6 @@ import dagger.Provides;
AssistModule.class,
BiometricsModule.class,
ClockModule.class,
CommunalModule.class,
DreamModule.class,
ControlsModule.class,
DemoModeModule.class,

View File

@@ -26,7 +26,7 @@ import dagger.Module;
import dagger.Provides;
/**
* Dagger Module providing Communal-related functionality.
* Dagger Module providing Dream-related functionality.
*/
@Module(includes = {
RegisteredComplicationsModule.class,

View File

@@ -1,82 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.collection.coordinator;
import androidx.annotation.NonNull;
import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import java.util.concurrent.Executor;
import javax.inject.Inject;
/**
* {@link CommunalCoordinator} prevents notifications from showing on the keyguard when the communal
* view is present.
*/
@CoordinatorScope
public class CommunalCoordinator implements Coordinator {
final Executor mExecutor;
final CommunalStateController mCommunalStateController;
final NotificationEntryManager mNotificationEntryManager;
final NotificationLockscreenUserManager mNotificationLockscreenUserManager;
@Inject
public CommunalCoordinator(@Main Executor executor,
NotificationEntryManager notificationEntryManager,
NotificationLockscreenUserManager notificationLockscreenUserManager,
CommunalStateController communalStateController) {
mExecutor = executor;
mNotificationEntryManager = notificationEntryManager;
mNotificationLockscreenUserManager = notificationLockscreenUserManager;
mCommunalStateController = communalStateController;
}
final NotifFilter mFilter = new NotifFilter("CommunalCoordinator") {
@Override
public boolean shouldFilterOut(@NonNull NotificationEntry entry, long now) {
return mCommunalStateController.getCommunalViewShowing();
}
};
final CommunalStateController.Callback mStateCallback = new CommunalStateController.Callback() {
@Override
public void onCommunalViewShowingChanged() {
mExecutor.execute(() -> {
mFilter.invalidateList();
mNotificationEntryManager.updateNotifications("Communal mode state changed");
});
}
};
@Override
public void attach(@NonNull NotifPipeline pipeline) {
pipeline.addPreGroupFilter(mFilter);
mCommunalStateController.addCallback(mStateCallback);
if (!pipeline.isNewPipelineEnabled()) {
mNotificationLockscreenUserManager.addKeyguardNotificationSuppressor(
entry -> mCommunalStateController.getCommunalViewShowing());
}
}
}

View File

@@ -45,7 +45,6 @@ class NotifCoordinatorsImpl @Inject constructor(
bubbleCoordinator: BubbleCoordinator,
headsUpCoordinator: HeadsUpCoordinator,
gutsCoordinator: GutsCoordinator,
communalCoordinator: CommunalCoordinator,
conversationCoordinator: ConversationCoordinator,
debugModeCoordinator: DebugModeCoordinator,
groupCountCoordinator: GroupCountCoordinator,
@@ -87,7 +86,6 @@ class NotifCoordinatorsImpl @Inject constructor(
mCoordinators.add(appOpsCoordinator)
mCoordinators.add(deviceProvisionedCoordinator)
mCoordinators.add(bubbleCoordinator)
mCoordinators.add(communalCoordinator)
mCoordinators.add(debugModeCoordinator)
mCoordinators.add(conversationCoordinator)
mCoordinators.add(groupCountCoordinator)

View File

@@ -120,13 +120,6 @@ import com.android.systemui.animation.LaunchAnimator;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.communal.CommunalHostView;
import com.android.systemui.communal.CommunalHostViewController;
import com.android.systemui.communal.CommunalHostViewPositionAlgorithm;
import com.android.systemui.communal.CommunalSource;
import com.android.systemui.communal.CommunalSourceMonitor;
import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.communal.dagger.CommunalViewComponent;
import com.android.systemui.controls.dagger.ControlsComponent;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.DisplayId;
@@ -209,7 +202,6 @@ import com.android.wm.shell.animation.FlingAnimationUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@@ -308,13 +300,10 @@ public class NotificationPanelViewController extends PanelViewController {
private final PulseExpansionHandler mPulseExpansionHandler;
private final KeyguardBypassController mKeyguardBypassController;
private final KeyguardUpdateMonitor mUpdateMonitor;
private final CommunalSourceMonitor mCommunalSourceMonitor;
private final CommunalStateController mCommunalStateController;
private final ConversationNotificationManager mConversationNotificationManager;
private final AuthController mAuthController;
private final MediaHierarchyManager mMediaHierarchyManager;
private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
private final CommunalViewComponent.Factory mCommunalViewComponentFactory;
private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
private final KeyguardQsUserSwitchComponent.Factory mKeyguardQsUserSwitchComponentFactory;
private final KeyguardUserSwitcherComponent.Factory mKeyguardUserSwitcherComponentFactory;
@@ -350,8 +339,6 @@ public class NotificationPanelViewController extends PanelViewController {
@VisibleForTesting QS mQs;
private FrameLayout mQsFrame;
private QsFrameTranslateController mQsFrameTranslateController;
@Nullable
private CommunalHostViewController mCommunalViewController;
private KeyguardStatusViewController mKeyguardStatusViewController;
private LockIconViewController mLockIconViewController;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
@@ -364,8 +351,6 @@ public class NotificationPanelViewController extends PanelViewController {
private VelocityTracker mQsVelocityTracker;
private boolean mQsTracking;
private CommunalHostView mCommunalView;
/**
* If set, the ongoing touch gesture might both trigger the expansion in {@link PanelView} and
* the expansion for quick settings.
@@ -413,12 +398,6 @@ public class NotificationPanelViewController extends PanelViewController {
private final KeyguardClockPositionAlgorithm.Result
mClockPositionResult =
new KeyguardClockPositionAlgorithm.Result();
private final CommunalHostViewPositionAlgorithm
mCommunalPositionAlgorithm =
new CommunalHostViewPositionAlgorithm();
private final CommunalHostViewPositionAlgorithm.Result
mCommunalPositionResult =
new CommunalHostViewPositionAlgorithm.Result();
private boolean mIsExpanding;
private boolean mBlockTouches;
@@ -523,10 +502,6 @@ public class NotificationPanelViewController extends PanelViewController {
mPanelAlphaAnimator.getProperty(), Interpolators.ALPHA_IN);
private final NotificationEntryManager mEntryManager;
private final CommunalSourceMonitor.Callback mCommunalSourceMonitorCallback;
private WeakReference<CommunalSource> mCommunalSource;
private final CommandQueue mCommandQueue;
private final NotificationLockscreenUserManager mLockscreenUserManager;
private final UserManager mUserManager;
@@ -686,32 +661,6 @@ public class NotificationPanelViewController extends PanelViewController {
}
};
private final CommunalStateController.Callback mCommunalStateCallback =
new CommunalStateController.Callback() {
@Override
public void onCommunalViewShowingChanged() {
mKeyguardStatusViewController.setKeyguardStatusViewVisibility(
mBarState,
mKeyguardStateController.isKeyguardFadingAway(),
mStatusBarStateController.goingToFullShade(),
mBarState);
if (mKeyguardUserSwitcherController != null) {
mKeyguardUserSwitcherController.setKeyguardUserSwitcherVisibility(
mBarState,
mKeyguardStateController.isKeyguardFadingAway(),
mStatusBarStateController.goingToFullShade(),
mBarState);
}
if (mKeyguardQsUserSwitchController != null) {
mKeyguardQsUserSwitchController.setKeyguardQsUserSwitchVisibility(
mBarState,
mKeyguardStateController.isKeyguardFadingAway(),
mStatusBarStateController.goingToFullShade(),
mBarState);
}
}
};
private final FalsingTapListener mFalsingTapListener = new FalsingTapListener() {
@Override
public void onDoubleTapRequired() {
@@ -737,7 +686,6 @@ public class NotificationPanelViewController extends PanelViewController {
FalsingCollector falsingCollector,
NotificationLockscreenUserManager notificationLockscreenUserManager,
NotificationEntryManager notificationEntryManager,
CommunalStateController communalStateController,
KeyguardStateController keyguardStateController,
StatusBarStateController statusBarStateController,
StatusBarWindowStateController statusBarWindowStateController,
@@ -747,7 +695,7 @@ public class NotificationPanelViewController extends PanelViewController {
LatencyTracker latencyTracker, PowerManager powerManager,
AccessibilityManager accessibilityManager, @DisplayId int displayId,
KeyguardUpdateMonitor keyguardUpdateMonitor,
CommunalSourceMonitor communalSourceMonitor, MetricsLogger metricsLogger,
MetricsLogger metricsLogger,
ActivityManager activityManager,
ConfigurationController configurationController,
Provider<FlingAnimationUtils.Builder> flingAnimationUtilsBuilder,
@@ -761,7 +709,6 @@ public class NotificationPanelViewController extends PanelViewController {
KeyguardQsUserSwitchComponent.Factory keyguardQsUserSwitchComponentFactory,
KeyguardUserSwitcherComponent.Factory keyguardUserSwitcherComponentFactory,
KeyguardStatusBarViewComponent.Factory keyguardStatusBarViewComponentFactory,
CommunalViewComponent.Factory communalViewComponentFactory,
LockscreenShadeTransitionController lockscreenShadeTransitionController,
NotificationGroupManagerLegacy groupManager,
NotificationIconAreaController notificationIconAreaController,
@@ -831,8 +778,6 @@ public class NotificationPanelViewController extends PanelViewController {
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
mGroupManager = groupManager;
mNotificationIconAreaController = notificationIconAreaController;
mCommunalStateController = communalStateController;
mCommunalViewComponentFactory = communalViewComponentFactory;
mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
mKeyguardStatusBarViewComponentFactory = keyguardStatusBarViewComponentFactory;
mDepthController = notificationShadeDepthController;
@@ -877,7 +822,6 @@ public class NotificationPanelViewController extends PanelViewController {
mThemeResId = mView.getContext().getThemeResId();
mKeyguardBypassController = bypassController;
mUpdateMonitor = keyguardUpdateMonitor;
mCommunalSourceMonitor = communalSourceMonitor;
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
lockscreenShadeTransitionController.setNotificationPanelController(this);
DynamicPrivacyControlListener
@@ -924,9 +868,6 @@ public class NotificationPanelViewController extends PanelViewController {
mNotificationPanelUnfoldAnimationController = unfoldComponent.map(
SysUIUnfoldComponent::getNotificationPanelUnfoldAnimationController);
mCommunalSourceMonitorCallback = (source) -> {
mUiExecutor.execute(() -> setCommunalSource(source));
};
mQsFrameTranslateController = qsFrameTranslateController;
updateUserSwitcherFlags();
onFinishInflate();
@@ -962,7 +903,6 @@ public class NotificationPanelViewController extends PanelViewController {
private void onFinishInflate() {
loadDimens();
mKeyguardStatusBar = mView.findViewById(R.id.keyguard_header);
mCommunalView = mView.findViewById(R.id.communal_host);
FrameLayout userAvatarContainer = null;
KeyguardUserSwitcherView keyguardUserSwitcherView = null;
@@ -984,20 +924,11 @@ public class NotificationPanelViewController extends PanelViewController {
.getKeyguardStatusBarViewController();
mKeyguardStatusBarViewController.init();
if (mCommunalView != null) {
CommunalViewComponent communalViewComponent =
mCommunalViewComponentFactory.build(mCommunalView);
mCommunalViewController =
communalViewComponent.getCommunalHostViewController();
mCommunalViewController.init();
}
mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent);
updateViewControllers(
mView.findViewById(R.id.keyguard_status_view),
userAvatarContainer,
keyguardUserSwitcherView,
mCommunalView);
keyguardUserSwitcherView);
NotificationStackScrollLayout stackScrollLayout = mView.findViewById(
R.id.notification_stack_scroller);
@@ -1088,8 +1019,7 @@ public class NotificationPanelViewController extends PanelViewController {
private void updateViewControllers(KeyguardStatusView keyguardStatusView,
FrameLayout userAvatarView,
KeyguardUserSwitcherView keyguardUserSwitcherView,
CommunalHostView communalView) {
KeyguardUserSwitcherView keyguardUserSwitcherView) {
// Re-associate the KeyguardStatusViewController
KeyguardStatusViewComponent statusViewComponent =
mKeyguardStatusViewComponentFactory.build(keyguardStatusView);
@@ -1282,7 +1212,7 @@ public class NotificationPanelViewController extends PanelViewController {
showKeyguardUserSwitcher /* enabled */);
updateViewControllers(mView.findViewById(R.id.keyguard_status_view), userAvatarView,
keyguardUserSwitcherView, mCommunalView);
keyguardUserSwitcherView);
// Update keyguard bottom area
int index = mView.indexOfChild(mKeyguardBottomArea);
@@ -1428,10 +1358,6 @@ public class NotificationPanelViewController extends PanelViewController {
int stackScrollerPadding;
boolean onKeyguard = isOnKeyguard();
if (onKeyguard) {
updateCommunalViewAppearance();
}
if (onKeyguard || forceClockUpdate) {
updateClockAppearance();
}
@@ -1457,22 +1383,6 @@ public class NotificationPanelViewController extends PanelViewController {
mAnimateNextPositionUpdate = false;
}
private void updateCommunalViewAppearance() {
if (mCommunalViewController == null) {
return;
}
float expandedFraction =
mScreenOffAnimationController.shouldExpandNotifications()
? 1.0f : getExpandedFraction();
mCommunalPositionAlgorithm.setup(expandedFraction, mCommunalView.getHeight());
mCommunalPositionAlgorithm.run(mCommunalPositionResult);
boolean animate =
mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending()
|| mAnimateNextPositionUpdate;
mCommunalViewController.updatePosition(mCommunalPositionResult.communalY, animate);
}
private void updateClockAppearance() {
int userSwitcherPreferredY = mStatusBarHeaderHeightKeyguard;
boolean bypassEnabled = mKeyguardBypassController.getBypassEnabled();
@@ -1547,9 +1457,8 @@ public class NotificationPanelViewController extends PanelViewController {
private void updateKeyguardStatusViewAlignment(boolean animate) {
boolean hasVisibleNotifications = mNotificationStackScrollLayoutController
.getVisibleNotificationCount() != 0 || mMediaDataManager.hasActiveMedia();
boolean hasCommunalSurface = mCommunalSource != null && mCommunalSource.get() != null;
boolean shouldBeCentered = !mShouldUseSplitNotificationShade
|| (!hasVisibleNotifications && !hasCommunalSurface) || mDozing;
boolean shouldBeCentered = !mShouldUseSplitNotificationShade || !hasVisibleNotifications
|| mDozing;
if (mStatusViewCentered != shouldBeCentered) {
mStatusViewCentered = shouldBeCentered;
ConstraintSet constraintSet = new ConstraintSet();
@@ -1579,11 +1488,6 @@ public class NotificationPanelViewController extends PanelViewController {
* @return the maximum keyguard notifications that can fit on the screen
*/
private int computeMaxKeyguardNotifications() {
// Do not show any notifications on the keyguard if a communal source is set.
if (mCommunalSource != null && mCommunalSource.get() != null) {
return 0;
}
float minPadding = mClockPositionAlgorithm.getMinStackScrollerPadding();
int notificationPadding = Math.max(
1, mResources.getDimensionPixelSize(R.dimen.notification_divider_height));
@@ -1707,12 +1611,6 @@ public class NotificationPanelViewController extends PanelViewController {
return true;
}
private void updateCommunal() {
if (mCommunalViewController != null) {
mCommunalViewController.setAlpha(mKeyguardOnlyContentAlpha);
}
}
private void updateClock() {
float alpha = mClockPositionResult.clockAlpha * mKeyguardOnlyContentAlpha;
mKeyguardStatusViewController.setAlpha(alpha);
@@ -2483,10 +2381,6 @@ public class NotificationPanelViewController extends PanelViewController {
mSplitShadeHeaderController.setShadeExpandedFraction(shadeExpandedFraction);
mSplitShadeHeaderController.setQsExpandedFraction(qsExpansionFraction);
mSplitShadeHeaderController.setShadeExpanded(mQsVisible);
if (mCommunalViewController != null) {
mCommunalViewController.updateQsExpansion(qsExpansionFraction);
}
}
private void onStackYChanged(boolean shouldAnimate) {
@@ -2849,10 +2743,6 @@ public class NotificationPanelViewController extends PanelViewController {
}
mTransitionToFullShadeQSPosition = position;
updateQsExpansion();
if (mCommunalViewController != null) {
mCommunalViewController.updateShadeExpansion(mTransitioningToFullShadeProgress);
}
}
/**
@@ -2876,7 +2766,6 @@ public class NotificationPanelViewController extends PanelViewController {
updateKeyguardBottomAreaAlpha();
}
updateClock();
updateCommunal();
}
private void trackMovement(MotionEvent event) {
@@ -4756,14 +4645,6 @@ public class NotificationPanelViewController extends PanelViewController {
goingToFullShade,
mBarState);
if (mCommunalViewController != null) {
mCommunalViewController.setKeyguardStatusViewVisibility(
statusBarState,
keyguardFadingAway,
goingToFullShade,
mBarState);
}
setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade);
mBarState = statusBarState;
@@ -4891,25 +4772,6 @@ public class NotificationPanelViewController extends PanelViewController {
setExpandedFraction(1f);
}
private void setCommunalSource(WeakReference<CommunalSource> source) {
CommunalSource existingSource = mCommunalSource != null ? mCommunalSource.get() : null;
if (existingSource != null) {
mCommunalViewController.show(null /*source*/);
}
mCommunalSource = source;
CommunalSource currentSource = mCommunalSource != null ? mCommunalSource.get() : null;
// Set source and register callback
if (currentSource != null && mCommunalViewController != null) {
mCommunalViewController.show(source);
}
updateKeyguardStatusViewAlignment(true /*animate*/);
updateMaxDisplayedNotifications(true /*recompute*/);
}
/**
* Sets the overstretch amount in raw pixels when dragging down.
*/
@@ -4927,7 +4789,6 @@ public class NotificationPanelViewController extends PanelViewController {
.addTagListener(QS.TAG, mFragmentListener);
mStatusBarStateController.addCallback(mStatusBarStateListener);
mConfigurationController.addCallback(mConfigurationListener);
mCommunalSourceMonitor.addCallback(mCommunalSourceMonitorCallback);
// Theme might have changed between inflating this view and attaching it to the
// window, so
// force a call to onThemeChanged
@@ -4935,7 +4796,6 @@ public class NotificationPanelViewController extends PanelViewController {
mFalsingManager.addTapListener(mFalsingTapListener);
mKeyguardIndicationController.init();
registerSettingsChangeListener();
mCommunalStateController.addCallback(mCommunalStateCallback);
}
@Override
@@ -4945,9 +4805,7 @@ public class NotificationPanelViewController extends PanelViewController {
.removeTagListener(QS.TAG, mFragmentListener);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
mConfigurationController.removeCallback(mConfigurationListener);
mCommunalSourceMonitor.removeCallback(mCommunalSourceMonitorCallback);
mFalsingManager.removeTapListener(mFalsingTapListener);
mCommunalStateController.removeCallback(mCommunalStateCallback);
}
}

View File

@@ -35,7 +35,6 @@ import com.android.keyguard.KeyguardVisibilityHelper;
import com.android.keyguard.dagger.KeyguardUserSwitcherScope;
import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.systemui.R;
import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.FalsingManager;
@@ -119,7 +118,6 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout>
@Main Resources resources,
ScreenLifecycle screenLifecycle,
UserSwitcherController userSwitcherController,
CommunalStateController communalStateController,
KeyguardStateController keyguardStateController,
FalsingManager falsingManager,
ConfigurationController configurationController,
@@ -138,10 +136,9 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout>
mFalsingManager = falsingManager;
mConfigurationController = configurationController;
mStatusBarStateController = statusBarStateController;
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, communalStateController,
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView,
keyguardStateController, dozeParameters,
screenOffAnimationController, /* animateYPos= */ false,
/* visibleOnCommunal= */ false);
screenOffAnimationController, /* animateYPos= */ false);
mUserSwitchDialogController = userSwitchDialogController;
mUiEventLogger = uiEventLogger;
}

View File

@@ -42,7 +42,6 @@ import com.android.keyguard.dagger.KeyguardUserSwitcherScope;
import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -158,7 +157,6 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS
LayoutInflater layoutInflater,
ScreenLifecycle screenLifecycle,
UserSwitcherController userSwitcherController,
CommunalStateController communalStateController,
KeyguardStateController keyguardStateController,
SysuiStatusBarStateController statusBarStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -174,10 +172,9 @@ public class KeyguardUserSwitcherController extends ViewController<KeyguardUserS
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mAdapter = new KeyguardUserAdapter(mContext, resources, layoutInflater,
mUserSwitcherController, this);
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, communalStateController,
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView,
keyguardStateController, dozeParameters,
screenOffAnimationController, /* animateYPos= */ false,
/* visibleOnCommunal= */ false);
screenOffAnimationController, /* animateYPos= */ false);
mBackground = new KeyguardUserSwitcherScrim(context);
}

View File

@@ -24,8 +24,6 @@ import android.content.IntentFilter;
import android.os.PatternMatcher;
import android.util.Log;
import com.android.systemui.communal.CommunalSource;
import com.google.android.collect.Lists;
import java.lang.ref.WeakReference;
@@ -36,8 +34,8 @@ import javax.inject.Inject;
/**
* {@link PackageObserver} allows for monitoring the system for changes relating to a particular
* package. This can be used by {@link CommunalSource} clients to detect when a related package
* has changed and reloading is necessary.
* package. This can be used by clients to detect when a related package has changed and reloading
* is necessary.
*/
public class PackageObserver implements Observer {
private static final String TAG = "PackageObserver";

View File

@@ -22,7 +22,6 @@ import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
@@ -50,8 +49,6 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
@Mock
private KeyguardStateController mKeyguardStateController;
@Mock
private CommunalStateController mCommunalStateController;
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
ConfigurationController mConfigurationController;
@@ -76,7 +73,6 @@ public class KeyguardStatusViewControllerTest extends SysuiTestCase {
mKeyguardClockSwitchController,
mKeyguardStateController,
mKeyguardUpdateMonitor,
mCommunalStateController,
mConfigurationController,
mDozeParameters,
mKeyguardUnlockAnimationController,

View File

@@ -1,92 +0,0 @@
/*
* Copyright (C) 2021 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.Mockito.verify;
import static org.mockito.Mockito.when;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.View;
import android.view.ViewPropertyAnimator;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
public class KeyguardVisibilityHelperTest extends SysuiTestCase {
@Mock
private CommunalStateController mCommunalStateController;
@Mock
private KeyguardStateController mKeyguardStateController;
@Mock
com.android.systemui.statusbar.phone.DozeParameters mDozeParameters;
@Mock
ScreenOffAnimationController mScreenOffAnimationController;
@Mock
ViewPropertyAnimator mViewPropertyAnimator;
@Mock
View mTargetView;
private KeyguardVisibilityHelper mKeyguardVisibilityHelper;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
when(mTargetView.animate()).thenReturn(mViewPropertyAnimator);
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mTargetView,
mCommunalStateController, mKeyguardStateController, mDozeParameters,
mScreenOffAnimationController, false, false);
}
@Test
public void testHideOnCommunal() {
// Verify view is hidden when communal is visible.
when(mCommunalStateController.getCommunalViewShowing()).thenReturn(true);
mKeyguardVisibilityHelper.setViewVisibility(StatusBarState.KEYGUARD, false,
false, StatusBarState.KEYGUARD);
verify(mTargetView).setVisibility(View.GONE);
verify(mTargetView).setAlpha(1.0f);
// Verify view is shown when communal is not visible.
when(mCommunalStateController.getCommunalViewShowing()).thenReturn(false);
mKeyguardVisibilityHelper.setViewVisibility(StatusBarState.KEYGUARD, false,
false, StatusBarState.KEYGUARD);
verify(mTargetView).setVisibility(View.VISIBLE);
}
@Test
public void testVisibleOnCommunal() {
when(mCommunalStateController.getCommunalViewShowing()).thenReturn(true);
when(mKeyguardStateController.isOccluded()).thenReturn(false);
// Verify that helpers constructed with visibility on communal are not hidden when communal
// is present.
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mTargetView,
mCommunalStateController, mKeyguardStateController, mDozeParameters,
mScreenOffAnimationController, false, true);
mKeyguardVisibilityHelper.setViewVisibility(StatusBarState.KEYGUARD, false,
false, StatusBarState.KEYGUARD);
verify(mTargetView).setVisibility(View.VISIBLE);
}
}

View File

@@ -1,242 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
import android.view.View;
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.lang.ref.WeakReference;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class CommunalHostViewControllerTest extends SysuiTestCase {
@Mock
private CommunalStateController mCommunalStateController;
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
private KeyguardStateController mKeyguardStateController;
@Mock
private StatusBarStateController mStatusBarStateController;
@Mock
private CommunalHostView mCommunalView;
@Mock
private DozeParameters mDozeParameters;
@Mock
private ScreenOffAnimationController mScreenOffAnimationController;
private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
private CommunalHostViewController mController;
@Mock
private CommunalSource mCommunalSource;
@Mock
private View mChildView;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
when(mKeyguardStateController.isShowing()).thenReturn(true);
when(mCommunalView.isAttachedToWindow()).thenReturn(true);
when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
mController = new CommunalHostViewController(mFakeExecutor, mCommunalStateController,
mKeyguardUpdateMonitor, mKeyguardStateController, mDozeParameters,
mScreenOffAnimationController, mStatusBarStateController, mCommunalView);
mController.init();
mFakeExecutor.runAllReady();
Mockito.clearInvocations(mCommunalView);
}
@Test
public void testShow() {
ArgumentCaptor<KeyguardStateController.Callback> callbackCapture =
ArgumentCaptor.forClass(KeyguardStateController.Callback.class);
// Capture callback value for later use.
verify(mKeyguardStateController).addCallback(callbackCapture.capture());
// Verify the communal view is shown when the controller is initialized with keyguard
// showing (see setup).
mController.show(new WeakReference<>(mCommunalSource));
mFakeExecutor.runAllReady();
verify(mCommunalView).setVisibility(View.VISIBLE);
// Trigger keyguard off to ensure visibility of communal view is changed accordingly.
when(mKeyguardStateController.isShowing()).thenReturn(false);
callbackCapture.getValue().onKeyguardShowingChanged();
mFakeExecutor.runAllReady();
verify(mCommunalView).setVisibility(View.INVISIBLE);
}
@Test
public void testHideOnOcclude() {
ArgumentCaptor<KeyguardUpdateMonitorCallback> callbackCapture =
ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
// Capture callback value for later use.
verify(mKeyguardUpdateMonitor).registerCallback(callbackCapture.capture());
// Establish a visible communal view.
mController.show(new WeakReference<>(mCommunalSource));
mFakeExecutor.runAllReady();
verify(mCommunalView).setVisibility(View.VISIBLE);
Mockito.clearInvocations(mCommunalView);
// Occlude.
Mockito.clearInvocations(mCommunalView);
callbackCapture.getValue().onKeyguardOccludedChanged(true);
mFakeExecutor.runAllReady();
verify(mCommunalView).setVisibility(View.INVISIBLE);
// Unocclude.
Mockito.clearInvocations(mCommunalView);
callbackCapture.getValue().onKeyguardOccludedChanged(false);
mFakeExecutor.runAllReady();
verify(mCommunalView).setVisibility(View.VISIBLE);
}
@Test
public void testReportOcclusion() {
// Ensure CommunalHostViewController reports view occluded when either the QS or Shade is
// expanded.
clearInvocations(mCommunalStateController);
mController.updateShadeExpansion(0);
verify(mCommunalStateController).setCommunalViewOccluded(false);
clearInvocations(mCommunalStateController);
mController.updateQsExpansion(.5f);
verify(mCommunalStateController).setCommunalViewOccluded(true);
clearInvocations(mCommunalStateController);
mController.updateShadeExpansion(.7f);
verify(mCommunalStateController).setCommunalViewOccluded(true);
clearInvocations(mCommunalStateController);
mController.updateShadeExpansion(0);
verify(mCommunalStateController).setCommunalViewOccluded(true);
clearInvocations(mCommunalStateController);
mController.updateQsExpansion(0f);
verify(mCommunalStateController).setCommunalViewOccluded(false);
clearInvocations(mCommunalStateController);
}
@Test
public void testCommunalStateControllerHideNotified() {
ArgumentCaptor<KeyguardUpdateMonitorCallback> callbackCapture =
ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
// Capture callback value for later use.
verify(mKeyguardUpdateMonitor).registerCallback(callbackCapture.capture());
// Establish a visible communal view.
mController.show(new WeakReference<>(mCommunalSource));
mFakeExecutor.runAllReady();
// Occlude
clearInvocations(mCommunalStateController);
callbackCapture.getValue().onKeyguardOccludedChanged(true);
mFakeExecutor.runAllReady();
// Verify state controller is notified communal view is hidden.
verify(mCommunalStateController).setCommunalViewShowing(false);
}
@Test
public void testAlphaPropagation() {
final float alpha = 0.8f;
// Ensure alpha setting is propagated to children.
when(mCommunalView.getChildCount()).thenReturn(1);
when(mCommunalView.getChildAt(0)).thenReturn(mChildView);
mController.setAlpha(alpha);
verify(mChildView).setAlpha(alpha);
verify(mCommunalView).setAlpha(alpha);
}
@Test
public void testMultipleShowRequestSuppression() {
// Ensure first request invokes source.
mController.show(new WeakReference<>(mCommunalSource));
mFakeExecutor.runAllReady();
verify(mCommunalSource).requestCommunalView(any());
clearInvocations(mCommunalSource);
// Ensure subsequent identical request is suppressed
mController.show(new WeakReference<>(mCommunalSource));
mFakeExecutor.runAllReady();
verify(mCommunalSource, never()).requestCommunalView(any());
}
@Test
public void testNoShowInvocationOnBouncer() {
ArgumentCaptor<KeyguardUpdateMonitorCallback> callbackCapture =
ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
// Capture callback value for later use.
verify(mKeyguardUpdateMonitor).registerCallback(callbackCapture.capture());
// Set source so it will be cleared if in invalid state.
mController.show(new WeakReference<>(mCommunalSource));
mFakeExecutor.runAllReady();
clearInvocations(mCommunalStateController, mCommunalView);
// Change bouncer to showing.
callbackCapture.getValue().onKeyguardBouncerChanged(true);
mFakeExecutor.runAllReady();
// Verify that there were no requests to remove all child views or set the communal
// state to not showing.
verify(mCommunalStateController, never()).setCommunalViewShowing(eq(false));
verify(mCommunalView, never()).removeAllViews();
}
}

View File

@@ -1,44 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal;
import static com.google.common.truth.Truth.assertThat;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.communal.CommunalHostViewPositionAlgorithm.Result;
import org.junit.Test;
@SmallTest
public class CommunalHostViewPositionAlgorithmTest extends SysuiTestCase {
@Test
public void testOutput() {
final float expansion = 0.25f;
final int height = 120;
final CommunalHostViewPositionAlgorithm algorithm = new CommunalHostViewPositionAlgorithm();
algorithm.setup(expansion, height);
final Result result = new Result();
algorithm.run(result);
// Verify the communal view is shifted offscreen vertically by the correct amount.
assertThat((1 - expansion) * -height).isEqualTo(result.communalY);
}
}

View File

@@ -1,119 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.os.Looper;
import android.os.UserHandle;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.communal.conditions.CommunalSettingCondition;
import com.android.systemui.util.condition.Condition;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.utils.os.FakeHandler;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class CommunalSettingConditionTest extends SysuiTestCase {
private FakeSettings mSecureSettings;
private CommunalSettingCondition mCondition;
@Before
public void setup() {
final FakeHandler handler = new FakeHandler(Looper.getMainLooper());
mSecureSettings = new FakeSettings();
mCondition = new CommunalSettingCondition(handler, mSecureSettings);
}
@Test
public void addCallback_communalSettingEnabled_immediatelyReportsTrue() {
updateCommunalSetting(true);
final Condition.Callback callback = mock(Condition.Callback.class);
mCondition.addCallback(callback);
verify(callback).onConditionChanged(mCondition);
assertThat(mCondition.isConditionMet()).isTrue();
}
@Test
public void addCallback_communalSettingDisabled_noReport() {
updateCommunalSetting(false);
final Condition.Callback callback = mock(Condition.Callback.class);
mCondition.addCallback(callback);
verify(callback, never()).onConditionChanged(eq(mCondition));
}
@Test
public void updateCallback_communalSettingEnabled_reportsTrue() {
updateCommunalSetting(false);
final Condition.Callback callback = mock(Condition.Callback.class);
mCondition.addCallback(callback);
clearInvocations(callback);
updateCommunalSetting(true);
verify(callback).onConditionChanged(mCondition);
assertThat(mCondition.isConditionMet()).isTrue();
}
@Test
public void updateCallback_communalSettingDisabled_reportsFalse() {
updateCommunalSetting(true);
final Condition.Callback callback = mock(Condition.Callback.class);
mCondition.addCallback(callback);
clearInvocations(callback);
updateCommunalSetting(false);
verify(callback).onConditionChanged(mCondition);
assertThat(mCondition.isConditionMet()).isFalse();
}
@Test
public void updateCallback_communalSettingDidNotChange_neverReportDup() {
updateCommunalSetting(true);
final Condition.Callback callback = mock(Condition.Callback.class);
mCondition.addCallback(callback);
clearInvocations(callback);
updateCommunalSetting(true);
verify(callback, never()).onConditionChanged(mCondition);
assertThat(mCondition.isConditionMet()).isTrue();
}
private void updateCommunalSetting(boolean value) {
mSecureSettings.putIntForUser(Settings.Secure.COMMUNAL_MODE_ENABLED, value ? 1 : 0,
UserHandle.USER_SYSTEM);
}
}

View File

@@ -1,169 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.condition.Monitor;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.lang.ref.WeakReference;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class CommunalSourceMonitorTest extends SysuiTestCase {
@Mock private Monitor mCommunalConditionsMonitor;
@Captor private ArgumentCaptor<Monitor.Callback> mConditionsCallbackCaptor;
private CommunalSourceMonitor mCommunalSourceMonitor;
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mCommunalSourceMonitor = new CommunalSourceMonitor(mExecutor, mCommunalConditionsMonitor);
}
@Test
public void testSourceAddedBeforeCallbackAdded() {
final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
final CommunalSource source = mock(CommunalSource.class);
setSource(source);
mCommunalSourceMonitor.addCallback(callback);
setConditionsMet(true);
verifyOnSourceAvailableCalledWith(callback, source);
}
@Test
public void testRemoveCallback() {
final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
final CommunalSource source = mock(CommunalSource.class);
mCommunalSourceMonitor.addCallback(callback);
mCommunalSourceMonitor.removeCallback(callback);
setSource(source);
verify(callback, never()).onSourceAvailable(any());
}
@Test
public void testAddCallbackWithConditionsMet() {
final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
final CommunalSource source = mock(CommunalSource.class);
mCommunalSourceMonitor.addCallback(callback);
setConditionsMet(true);
clearInvocations(callback);
setSource(source);
verifyOnSourceAvailableCalledWith(callback, source);
}
@Test
public void testAddCallbackWithConditionsNotMet() {
final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
final CommunalSource source = mock(CommunalSource.class);
mCommunalSourceMonitor.addCallback(callback);
setConditionsMet(false);
setSource(source);
verify(callback, never()).onSourceAvailable(any());
}
@Test
public void testConditionsAreMetAfterCallbackAdded() {
final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
final CommunalSource source = mock(CommunalSource.class);
mCommunalSourceMonitor.addCallback(callback);
setSource(source);
// The callback should not have executed since communal is disabled.
verify(callback, never()).onSourceAvailable(any());
// The callback should execute when all conditions are met.
setConditionsMet(true);
verifyOnSourceAvailableCalledWith(callback, source);
}
@Test
public void testConditionsNoLongerMetAfterCallbackAdded() {
final CommunalSourceMonitor.Callback callback = mock(CommunalSourceMonitor.Callback.class);
final CommunalSource source = mock(CommunalSource.class);
mCommunalSourceMonitor.addCallback(callback);
setSource(source);
setConditionsMet(true);
verifyOnSourceAvailableCalledWith(callback, source);
// The callback should execute again when conditions are no longer met, with a value of
// null.
setConditionsMet(false);
verify(callback).onSourceAvailable(null);
}
private void verifyOnSourceAvailableCalledWith(CommunalSourceMonitor.Callback callback,
CommunalSource source) {
final ArgumentCaptor<WeakReference<CommunalSource>> sourceCapture =
ArgumentCaptor.forClass(WeakReference.class);
verify(callback).onSourceAvailable(sourceCapture.capture());
assertThat(sourceCapture.getValue().get()).isEqualTo(source);
}
// Pushes an update on whether the communal conditions are met, assuming that a callback has
// been registered with the communal conditions monitor.
private void setConditionsMet(boolean value) {
mExecutor.runAllReady();
verify(mCommunalConditionsMonitor).addCallback(mConditionsCallbackCaptor.capture());
final Monitor.Callback conditionsCallback =
mConditionsCallbackCaptor.getValue();
conditionsCallback.onConditionsChanged(value);
mExecutor.runAllReady();
}
private void setSource(CommunalSource source) {
mCommunalSourceMonitor.setSource(source);
mExecutor.runAllReady();
}
}

View File

@@ -1,205 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.concurrency.FakeExecutor;;
import com.android.systemui.util.ref.GcWeakReference;
import com.android.systemui.util.time.FakeSystemClock;
import com.google.common.util.concurrent.ListenableFuture;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.Optional;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class CommunalSourcePrimerTest extends SysuiTestCase {
private static final String TEST_COMPONENT_NAME = "com.google.tests/.CommunalService";
private static final int MAX_RETRIES = 5;
private static final int RETRY_DELAY_MS = 1000;
private static final int CONNECTION_MIN_DURATION_MS = 5000;
// A simple implementation of {@link CommunalSource.Observer} to capture a callback value.
// Used to ensure the references to a {@link CommunalSource.Observer.Callback} can be fully
// removed.
private static class FakeObserver implements CommunalSource.Observer {
public GcWeakReference<Callback> mLastCallback;
@Override
public void addCallback(Callback callback) {
mLastCallback = new GcWeakReference<>(callback);
}
@Override
public void removeCallback(Callback callback) {
if (mLastCallback.get() == callback) {
mLastCallback = null;
}
}
}
// A simple implementation of {@link CommunalSource} to capture callback values. This
// implementation better emulates the {@link WeakReference} wrapping behavior of
// {@link CommunalSource} implementations than a mock.
private static class FakeSource implements CommunalSource {
@Override
public ListenableFuture<CommunalViewResult> requestCommunalView(Context context) {
return null;
}
}
@Mock
private Context mContext;
@Mock
private Resources mResources;
private FakeSystemClock mFakeClock = new FakeSystemClock();
private FakeExecutor mFakeExecutor = new FakeExecutor(mFakeClock);
private FakeSource mSource = new FakeSource();
@Mock
private CommunalSourceMonitor mCommunalSourceMonitor;
@Mock
private CommunalSource.Connector mConnector;
@Mock
private CommunalSource.Connection mConnection;
private FakeObserver mObserver = new FakeObserver();
private CommunalSourcePrimer mPrimer;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
when(mResources.getInteger(R.integer.config_communalSourceMaxReconnectAttempts))
.thenReturn(MAX_RETRIES);
when(mResources.getInteger(R.integer.config_communalSourceReconnectBaseDelay))
.thenReturn(RETRY_DELAY_MS);
when(mResources.getInteger(R.integer.config_communalSourceReconnectBaseDelay))
.thenReturn(RETRY_DELAY_MS);
when(mResources.getString(R.string.config_communalSourceComponent))
.thenReturn(TEST_COMPONENT_NAME);
when(mResources.getInteger(R.integer.config_connectionMinDuration))
.thenReturn(CONNECTION_MIN_DURATION_MS);
mPrimer = new CommunalSourcePrimer(mContext, mResources, mFakeClock, mFakeExecutor,
mCommunalSourceMonitor, Optional.of(mConnector), Optional.of(mObserver));
}
private CommunalSource.Connection.Callback captureCallbackAndSend(
CommunalSource.Connector connector, Optional<CommunalSource> source) {
ArgumentCaptor<CommunalSource.Connection.Callback> connectionCallback =
ArgumentCaptor.forClass(CommunalSource.Connection.Callback.class);
verify(connector).connect(connectionCallback.capture());
Mockito.clearInvocations(connector);
final CommunalSource.Connection.Callback callback = connectionCallback.getValue();
callback.onSourceEstablished(source);
return callback;
}
@Test
public void testConnect() {
mPrimer.onBootCompleted();
captureCallbackAndSend(mConnector, Optional.of(mSource));
verify(mCommunalSourceMonitor).setSource(mSource);
}
@Test
public void testRetryOnBindFailure() throws Exception {
mPrimer.onBootCompleted();
// Verify attempts happen. Note that we account for the retries plus initial attempt, which
// is not scheduled.
for (int attemptCount = 0; attemptCount < MAX_RETRIES + 1; attemptCount++) {
captureCallbackAndSend(mConnector, Optional.empty());
mFakeExecutor.advanceClockToNext();
mFakeExecutor.runAllReady();
}
verify(mCommunalSourceMonitor, never()).setSource(Mockito.notNull());
}
@Test
public void testRetryOnDisconnectFailure() throws Exception {
mPrimer.onBootCompleted();
// Verify attempts happen. Note that we account for the retries plus initial attempt, which
// is not scheduled.
for (int attemptCount = 0; attemptCount < MAX_RETRIES + 1; attemptCount++) {
final CommunalSource.Connection.Callback callback =
captureCallbackAndSend(mConnector, Optional.of(mSource));
verify(mCommunalSourceMonitor).setSource(Mockito.notNull());
clearInvocations(mCommunalSourceMonitor);
callback.onDisconnected();
mFakeExecutor.advanceClockToNext();
mFakeExecutor.runAllReady();
}
verify(mConnector, never()).connect(any());
}
@Test
public void testAttemptOnPackageChange() {
mPrimer.onBootCompleted();
captureCallbackAndSend(mConnector, Optional.empty());
mObserver.mLastCallback.get().onSourceChanged();
verify(mConnector, times(1)).connect(any());
}
@Test
public void testDisconnect() {
mPrimer.onBootCompleted();
final CommunalSource.Connection.Callback callback =
captureCallbackAndSend(mConnector, Optional.of(mSource));
verify(mCommunalSourceMonitor).setSource(mSource);
mFakeClock.advanceTime(CONNECTION_MIN_DURATION_MS + 1);
callback.onDisconnected();
verify(mConnector).connect(any());
}
}

View File

@@ -1,91 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class CommunalStateControllerTest extends SysuiTestCase {
@Mock
private CommunalStateController.Callback mCallback;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testDefaultCommunalViewShowingState() {
// The state controller should report the communal view as not showing by default.
final CommunalStateController stateController = new CommunalStateController();
assertThat(stateController.getCommunalViewShowing()).isFalse();
}
@Test
public void testNotifyCommunalSurfaceShow() {
final CommunalStateController stateController = new CommunalStateController();
stateController.addCallback(mCallback);
// Verify setting communal view to showing propagates to callback.
stateController.setCommunalViewShowing(true);
verify(mCallback).onCommunalViewShowingChanged();
assertThat(stateController.getCommunalViewShowing()).isTrue();
clearInvocations(mCallback);
// Verify setting communal view to not showing propagates to callback.
stateController.setCommunalViewShowing(false);
verify(mCallback).onCommunalViewShowingChanged();
assertThat(stateController.getCommunalViewShowing()).isFalse();
}
@Test
public void testCallbackRegistration() {
final CommunalStateController stateController = new CommunalStateController();
stateController.addCallback(mCallback);
// Verify setting communal view to showing propagates to callback.
stateController.setCommunalViewShowing(true);
verify(mCallback).onCommunalViewShowingChanged();
clearInvocations(mCallback);
stateController.removeCallback(mCallback);
clearInvocations(mCallback);
// Verify callback not invoked after removing from state controller.
stateController.setCommunalViewShowing(false);
verify(mCallback, never()).onCommunalViewShowingChanged();
}
}

View File

@@ -1,77 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.communal;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.verify;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.testing.AndroidTestingRunner;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
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)
public class PackageObserverTest extends SysuiTestCase {
private static final String PACKAGE_NAME = "com.foo.bar";
@Mock
Context mContext;
@Mock
CommunalSource.Observer.Callback mCallback;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testChange() {
final PackageObserver observer = new PackageObserver(mContext, PACKAGE_NAME);
final ArgumentCaptor<BroadcastReceiver> receiverCapture =
ArgumentCaptor.forClass(BroadcastReceiver.class);
observer.addCallback(mCallback);
// Verify broadcast receiver registered.
verify(mContext).registerReceiver(receiverCapture.capture(), any(), anyInt());
// Simulate package change.
receiverCapture.getValue().onReceive(mContext, new Intent());
// Check that callback was informed.
verify(mCallback).onSourceChanged();
observer.removeCallback(mCallback);
// Make sure receiver is unregistered on last callback removal
verify(mContext).unregisterReceiver(receiverCapture.getValue());
}
}

View File

@@ -1,106 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.collection.coordinator;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.Pluggable;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
public class CommunalCoordinatorTest extends SysuiTestCase {
private final FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
@Mock
CommunalStateController mCommunalStateController;
@Mock
NotificationEntryManager mNotificationEntryManager;
@Mock
NotificationLockscreenUserManager mNotificationLockscreenUserManager;
@Mock
NotifPipeline mNotifPipeline;
@Mock
NotificationEntry mNotificationEntry;
@Mock
Pluggable.PluggableListener mFilterListener;
CommunalCoordinator mCoordinator;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mCoordinator = new CommunalCoordinator(mExecutor, mNotificationEntryManager,
mNotificationLockscreenUserManager, mCommunalStateController);
}
@Test
public void testNotificationSuppressionInCommunal() {
mCoordinator.attach(mNotifPipeline);
final ArgumentCaptor<CommunalStateController.Callback> stateCallbackCaptor =
ArgumentCaptor.forClass(CommunalStateController.Callback.class);
verify(mCommunalStateController).addCallback(stateCallbackCaptor.capture());
final CommunalStateController.Callback stateCallback = stateCallbackCaptor.getValue();
final ArgumentCaptor<NotifFilter> filterCaptor =
ArgumentCaptor.forClass(NotifFilter.class);
verify(mNotifPipeline).addPreGroupFilter(filterCaptor.capture());
final NotifFilter filter = filterCaptor.getValue();
// Verify that notifications are not filtered out by default.
assertThat(filter.shouldFilterOut(mNotificationEntry, 0)).isFalse();
filter.setInvalidationListener(mFilterListener);
// Verify that notifications are filtered out when communal is showing and that the filter
// pipeline is notified.
when(mCommunalStateController.getCommunalViewShowing()).thenReturn(true);
stateCallback.onCommunalViewShowingChanged();
// Make sure callback depends on executor to run.
verify(mFilterListener, never()).onPluggableInvalidated(any());
verify(mNotificationEntryManager, never()).updateNotifications(any());
mExecutor.runAllReady();
verify(mFilterListener).onPluggableInvalidated(any());
verify(mNotificationEntryManager).updateNotifications(any());
assertThat(filter.shouldFilterOut(mNotificationEntry, 0)).isTrue();
}
}

View File

@@ -28,7 +28,6 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeast;
@@ -88,12 +87,6 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.classifier.FalsingCollectorFake;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.communal.CommunalHostView;
import com.android.systemui.communal.CommunalHostViewController;
import com.android.systemui.communal.CommunalSource;
import com.android.systemui.communal.CommunalSourceMonitor;
import com.android.systemui.communal.CommunalStateController;
import com.android.systemui.communal.dagger.CommunalViewComponent;
import com.android.systemui.controls.dagger.ControlsComponent;
import com.android.systemui.doze.DozeLog;
import com.android.systemui.dump.DumpManager;
@@ -157,7 +150,6 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.Optional;
@@ -271,21 +263,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
@Mock
private KeyguardStatusBarViewComponent mKeyguardStatusBarViewComponent;
@Mock
private CommunalViewComponent.Factory mCommunalViewComponentFactory;
@Mock
private CommunalViewComponent mCommunalViewComponent;
@Mock
private CommunalHostViewController mCommunalHostViewController;
@Mock
private CommunalSourceMonitor mCommunalSourceMonitor;
@Mock
private CommunalSource mCommunalSource;
@Mock
private CommunalHostView mCommunalHostView;
@Mock
private CommunalStateController mCommunalStateController;
private CommunalStateController.Callback mCommunalStateControllerCallback;
@Mock
private KeyguardClockSwitchController mKeyguardClockSwitchController;
@Mock
private KeyguardStatusViewController mKeyguardStatusViewController;
@@ -401,7 +378,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
when(mView.findViewById(R.id.keyguard_clock_container)).thenReturn(mKeyguardClockSwitch);
when(mView.findViewById(R.id.notification_stack_scroller))
.thenReturn(mNotificationStackScrollLayout);
when(mView.findViewById(R.id.communal_host)).thenReturn(mCommunalHostView);
when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(1000);
when(mNotificationStackScrollLayoutController.getHeadsUpCallback())
.thenReturn(mHeadsUpCallback);
@@ -467,10 +443,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
.thenReturn(mKeyguardStatusBarViewComponent);
when(mKeyguardStatusBarViewComponent.getKeyguardStatusBarViewController())
.thenReturn(mKeyguardStatusBarViewController);
when(mCommunalViewComponentFactory.build(any()))
.thenReturn(mCommunalViewComponent);
when(mCommunalViewComponent.getCommunalHostViewController())
.thenReturn(mCommunalHostViewController);
when(mLayoutInflater.inflate(eq(R.layout.keyguard_status_view), any(), anyBoolean()))
.thenReturn(mKeyguardStatusView);
when(mLayoutInflater.inflate(eq(R.layout.keyguard_user_switcher), any(), anyBoolean()))
@@ -499,13 +471,13 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
coordinator, expansionHandler, mDynamicPrivacyController, mKeyguardBypassController,
mFalsingManager, new FalsingCollectorFake(),
mNotificationLockscreenUserManager, mNotificationEntryManager,
mCommunalStateController, mKeyguardStateController,
mKeyguardStateController,
mStatusBarStateController,
mStatusBarWindowStateController,
mNotificationShadeWindowController,
mDozeLog, mDozeParameters, mCommandQueue, mVibratorHelper,
mLatencyTracker, mPowerManager, mAccessibilityManager, 0, mUpdateMonitor,
mCommunalSourceMonitor, mMetricsLogger, mActivityManager, mConfigurationController,
mMetricsLogger, mActivityManager, mConfigurationController,
() -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
mConversationNotificationManager, mMediaHiearchyManager,
mStatusBarKeyguardViewManager,
@@ -515,7 +487,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mKeyguardQsUserSwitchComponentFactory,
mKeyguardUserSwitcherComponentFactory,
mKeyguardStatusBarViewComponentFactory,
mCommunalViewComponentFactory,
mLockscreenShadeTransitionController,
mGroupManager,
mNotificationAreaController,
@@ -1021,81 +992,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
verify(mKeyguardStatusViewController, never()).displayClock(LARGE, /* animate */ true);
}
@Test
public void testCommunalhostViewControllerInit() {
verify(mCommunalHostViewController, times(1)).init();
clearInvocations(mCommunalHostViewController);
givenViewAttached();
verify(mCommunalHostViewController, never()).init();
}
@Test
public void testCommunalSourceListening() {
final ArgumentCaptor<CommunalSourceMonitor.Callback> monitorCallback =
ArgumentCaptor.forClass(CommunalSourceMonitor.Callback.class);
givenViewAttached();
verify(mCommunalSourceMonitor).addCallback(monitorCallback.capture());
final ArgumentCaptor<WeakReference<CommunalSource>> sourceCapture =
ArgumentCaptor.forClass(WeakReference.class);
monitorCallback.getValue().onSourceAvailable(new WeakReference<>(mCommunalSource));
mExecutor.runAllReady();
verify(mCommunalHostViewController).show(sourceCapture.capture());
assertThat(sourceCapture.getValue().get()).isEqualTo(mCommunalSource);
clearInvocations(mCommunalHostViewController);
givenViewDetached();
verify(mCommunalSourceMonitor).removeCallback(any());
}
@Test
public void testKeyguardStatusViewUpdatedWithCommunalPresence() {
givenViewAttached();
when(mResources.getBoolean(
com.android.internal.R.bool.config_keyguardUserSwitcher)).thenReturn(true);
updateMultiUserSetting(true);
ArgumentCaptor<CommunalStateController.Callback> communalCallbackCapture =
ArgumentCaptor.forClass(CommunalStateController.Callback.class);
verify(mCommunalStateController).addCallback(communalCallbackCapture.capture());
final CommunalStateController.Callback communalStateControllerCallback =
communalCallbackCapture.getValue();
clearInvocations(mKeyguardStatusViewController, mKeyguardUserSwitcherController);
// Ensure changes in communal visibility leads to setting the keyguard status view
// visibility.
communalStateControllerCallback.onCommunalViewShowingChanged();
verify(mKeyguardStatusViewController).setKeyguardStatusViewVisibility(anyInt(),
anyBoolean(), anyBoolean(), anyInt());
verify(mKeyguardUserSwitcherController).setKeyguardUserSwitcherVisibility(anyInt(),
anyBoolean(), anyBoolean(), anyInt());
}
@Test
public void testCommunalAlphaUpdate() {
// Verify keyguard content alpha changes are propagate. Note the actual value set is not
// checked since an interpolation is applied to the incoming value.
mNotificationPanelViewController.setKeyguardOnlyContentAlpha(0.8f);
verify(mCommunalHostViewController).setAlpha(anyFloat());
}
@Test
public void testCommunalPositionUpdate() {
// Verify that the communal position is updated on interaction with the
// NotificationPanelViewController. Note that there a number of paths where the position
// might be updated and therefore the check isn't strictly on a single invocation.
clearInvocations(mCommunalHostViewController);
final View.OnLayoutChangeListener layoutChangeListener =
mNotificationPanelViewController.createLayoutChangeListener();
mNotificationPanelViewController.mStatusBarStateController.setState(KEYGUARD);
layoutChangeListener.onLayoutChange(mView, 0, 0, 200, 200, 0, 0, 200, 200);
verify(mCommunalHostViewController, atLeast(1))
.updatePosition(anyInt(), anyBoolean());
}
private void triggerPositionClockAndNotifications() {
mNotificationPanelViewController.closeQs();
}

View File

@@ -26,7 +26,6 @@ import androidx.test.filters.SmallTest
import com.android.internal.logging.UiEventLogger
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.CommunalStateController
import com.android.systemui.keyguard.ScreenLifecycle
import com.android.systemui.plugins.FalsingManager
import com.android.systemui.qs.user.UserSwitchDialogController
@@ -54,9 +53,6 @@ class KeyguardQsUserSwitchControllerTest : SysuiTestCase() {
@Mock
private lateinit var userSwitcherController: UserSwitcherController
@Mock
private lateinit var communalStateController: CommunalStateController
@Mock
private lateinit var keyguardStateController: KeyguardStateController
@@ -99,7 +95,6 @@ class KeyguardQsUserSwitchControllerTest : SysuiTestCase() {
context.resources,
screenLifecycle,
userSwitcherController,
communalStateController,
keyguardStateController,
falsingManager,
configurationController,