Merge "[SB Refactor] Define a new status bar wifi view that can be swapped in/out with the old view. Define a skeleton ViewBinder for the new view." into tm-qpr-dev

This commit is contained in:
Caitlin Shkuratov
2022-08-23 16:27:46 +00:00
committed by Android (Google) Code Review
26 changed files with 560 additions and 118 deletions

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
**
** Copyright 2022, 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.
*/
-->
<com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/wifi_combo"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical" >
<include layout="@layout/status_bar_wifi_group_inner" />
</com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView>

View File

@@ -18,70 +18,11 @@
-->
<com.android.systemui.statusbar.StatusBarWifiView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:systemui="http://schemas.android.com/apk/res-auto"
android:id="@+id/wifi_combo"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical" >
<com.android.keyguard.AlphaOptimizedLinearLayout
android:id="@+id/wifi_group"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:layout_marginStart="2.5dp"
>
<FrameLayout
android:id="@+id/inout_container"
android:layout_height="17dp"
android:layout_width="wrap_content"
android:gravity="center_vertical" >
<ImageView
android:id="@+id/wifi_in"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_down"
android:visibility="gone"
android:paddingEnd="2dp"
/>
<ImageView
android:id="@+id/wifi_out"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_up"
android:paddingEnd="2dp"
android:visibility="gone"
/>
</FrameLayout>
<FrameLayout
android:id="@+id/wifi_combo"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:gravity="center_vertical" >
<com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/wifi_signal"
android:layout_height="@dimen/status_bar_wifi_signal_size"
android:layout_width="@dimen/status_bar_wifi_signal_size" />
</FrameLayout>
<include layout="@layout/status_bar_wifi_group_inner" />
<View
android:id="@+id/wifi_signal_spacer"
android:layout_width="@dimen/status_bar_wifi_signal_spacer_width"
android:layout_height="4dp"
android:visibility="gone" />
<!-- Looks like CarStatusBar uses this... -->
<ViewStub
android:id="@+id/connected_device_signals_stub"
android:layout="@layout/connected_device_signal"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<View
android:id="@+id/wifi_airplane_spacer"
android:layout_width="@dimen/status_bar_airplane_spacer_width"
android:layout_height="4dp"
android:visibility="gone"
/>
</com.android.keyguard.AlphaOptimizedLinearLayout>
</com.android.systemui.statusbar.StatusBarWifiView>
</com.android.systemui.statusbar.StatusBarWifiView>

View File

@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
**
** Copyright 2022, 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.
*/
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<com.android.keyguard.AlphaOptimizedLinearLayout
android:id="@+id/wifi_group"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:layout_marginStart="2.5dp"
>
<FrameLayout
android:id="@+id/inout_container"
android:layout_height="17dp"
android:layout_width="wrap_content"
android:gravity="center_vertical" >
<ImageView
android:id="@+id/wifi_in"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_down"
android:visibility="gone"
android:paddingEnd="2dp"
/>
<ImageView
android:id="@+id/wifi_out"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:src="@drawable/ic_activity_up"
android:paddingEnd="2dp"
android:visibility="gone"
/>
</FrameLayout>
<FrameLayout
android:id="@+id/wifi_combo"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:gravity="center_vertical" >
<com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/wifi_signal"
android:layout_height="@dimen/status_bar_wifi_signal_size"
android:layout_width="@dimen/status_bar_wifi_signal_size" />
</FrameLayout>
<View
android:id="@+id/wifi_signal_spacer"
android:layout_width="@dimen/status_bar_wifi_signal_spacer_width"
android:layout_height="4dp"
android:visibility="gone" />
<!-- Looks like CarStatusBar uses this... -->
<ViewStub
android:id="@+id/connected_device_signals_stub"
android:layout="@layout/connected_device_signal"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<View
android:id="@+id/wifi_airplane_spacer"
android:layout_width="@dimen/status_bar_airplane_spacer_width"
android:layout_height="4dp"
android:visibility="gone"
/>
</com.android.keyguard.AlphaOptimizedLinearLayout>
</merge>

View File

@@ -155,7 +155,11 @@ public class Flags {
public static final ReleasedFlag STATUS_BAR_LETTERBOX_APPEARANCE =
new ReleasedFlag(603, false);
public static final UnreleasedFlag NEW_STATUS_BAR_PIPELINE = new UnreleasedFlag(604, true);
public static final UnreleasedFlag NEW_STATUS_BAR_PIPELINE_BACKEND =
new UnreleasedFlag(604, true);
public static final UnreleasedFlag NEW_STATUS_BAR_PIPELINE_FRONTEND =
new UnreleasedFlag(605, true);
/***************************************/
// 700 - dialer/calls

View File

@@ -80,7 +80,8 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
FeatureFlags featureFlags,
VariableDateViewController.Factory variableDateViewControllerFactory,
BatteryMeterViewController batteryMeterViewController,
StatusBarContentInsetsProvider statusBarContentInsetsProvider) {
StatusBarContentInsetsProvider statusBarContentInsetsProvider,
StatusBarIconController.TintedIconManager.Factory tintedIconManagerFactory) {
super(view);
mPrivacyIconsController = headerPrivacyIconsController;
mStatusBarIconController = statusBarIconController;
@@ -103,7 +104,7 @@ class QuickStatusBarHeaderController extends ViewController<QuickStatusBarHeader
mView.requireViewById(R.id.date_clock)
);
mIconManager = new StatusBarIconController.TintedIconManager(mIconContainer, featureFlags);
mIconManager = tintedIconManagerFactory.create(mIconContainer);
mDemoModeReceiver = new ClockDemoModeReceiver(mClockView);
mColorExtractor = colorExtractor;
mOnColorsChangedListener = (extractor, which) -> {

View File

@@ -77,6 +77,7 @@ import javax.inject.Named
class LargeScreenShadeHeaderController @Inject constructor(
@Named(LARGE_SCREEN_SHADE_HEADER) private val header: View,
private val statusBarIconController: StatusBarIconController,
private val tintedIconManagerFactory: StatusBarIconController.TintedIconManager.Factory,
private val privacyIconsController: HeaderPrivacyIconsController,
private val insetsProvider: StatusBarContentInsetsProvider,
private val configurationController: ConfigurationController,
@@ -259,7 +260,7 @@ class LargeScreenShadeHeaderController @Inject constructor(
batteryMeterViewController.ignoreTunerUpdates()
batteryIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
iconManager = StatusBarIconController.TintedIconManager(iconContainer, featureFlags)
iconManager = tintedIconManagerFactory.create(iconContainer)
iconManager.setTint(
Utils.getColorAttrDefaultColor(header.context, android.R.attr.textColorPrimary)
)

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2022 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
import android.content.Context
import android.util.AttributeSet
import android.widget.FrameLayout
/**
* A temporary base class that's shared between our old status bar wifi view implementation
* ([StatusBarWifiView]) and our new status bar wifi view implementation
* ([ModernStatusBarWifiView]).
*
* Once our refactor is over, we should be able to delete this go-between class and the old view
* class.
*/
abstract class BaseStatusBarWifiView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttrs: Int = 0,
) : FrameLayout(context, attrs, defStyleAttrs), StatusIconDisplayable

View File

@@ -28,7 +28,6 @@ import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -41,8 +40,7 @@ import java.util.ArrayList;
/**
* Start small: StatusBarWifiView will be able to layout from a WifiIconState
*/
public class StatusBarWifiView extends FrameLayout implements DarkReceiver,
StatusIconDisplayable {
public class StatusBarWifiView extends BaseStatusBarWifiView implements DarkReceiver {
private static final String TAG = "StatusBarWifiView";
/// Used to show etc dots
@@ -80,11 +78,6 @@ public class StatusBarWifiView extends FrameLayout implements DarkReceiver,
super(context, attrs, defStyleAttr);
}
public StatusBarWifiView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public void setSlot(String slot) {
mSlot = slot;
}

View File

@@ -23,7 +23,7 @@ import com.android.settingslib.SignalIcon.IconGroup;
/** */
public class WifiIcons {
static final int[] WIFI_FULL_ICONS = {
public static final int[] WIFI_FULL_ICONS = {
com.android.internal.R.drawable.ic_wifi_signal_0,
com.android.internal.R.drawable.ic_wifi_signal_1,
com.android.internal.R.drawable.ic_wifi_signal_2,

View File

@@ -225,6 +225,7 @@ public class DemoStatusIcons extends StatusIconContainer implements DemoMode, Da
public void addDemoWifiView(WifiIconState state) {
Log.d(TAG, "addDemoWifiView: ");
// TODO(b/238425913): Migrate this view to {@code ModernStatusBarWifiView}.
StatusBarWifiView view = StatusBarWifiView.fromContext(mContext, state.slot);
int viewIndex = getChildCount();

View File

@@ -40,6 +40,7 @@ import com.android.systemui.demomode.DemoModeCommandReceiver;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.DarkIconDispatcher;
import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.BaseStatusBarWifiView;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.StatusBarMobileView;
import com.android.systemui.statusbar.StatusBarWifiView;
@@ -47,12 +48,16 @@ import com.android.systemui.statusbar.StatusIconDisplayable;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.CallIndicatorIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
import com.android.systemui.statusbar.pipeline.wifi.ui.view.ModernStatusBarWifiView;
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel;
import com.android.systemui.util.Assert;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Provider;
public interface StatusBarIconController {
@@ -128,8 +133,12 @@ public interface StatusBarIconController {
private final DarkIconDispatcher mDarkIconDispatcher;
private int mIconHPadding;
public DarkIconManager(LinearLayout linearLayout, FeatureFlags featureFlags) {
super(linearLayout, featureFlags);
public DarkIconManager(
LinearLayout linearLayout,
FeatureFlags featureFlags,
StatusBarPipelineFlags statusBarPipelineFlags,
Provider<WifiViewModel> wifiViewModelProvider) {
super(linearLayout, featureFlags, statusBarPipelineFlags, wifiViewModelProvider);
mIconHPadding = mContext.getResources().getDimensionPixelSize(
R.dimen.status_bar_icon_padding);
mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class);
@@ -183,14 +192,40 @@ public interface StatusBarIconController {
mDarkIconDispatcher.removeDarkReceiver(mDemoStatusIcons);
super.exitDemoMode();
}
@SysUISingleton
public static class Factory {
private final FeatureFlags mFeatureFlags;
private final StatusBarPipelineFlags mStatusBarPipelineFlags;
private final Provider<WifiViewModel> mWifiViewModelProvider;
@Inject
public Factory(
FeatureFlags featureFlags,
StatusBarPipelineFlags statusBarPipelineFlags,
Provider<WifiViewModel> wifiViewModelProvider) {
mFeatureFlags = featureFlags;
mStatusBarPipelineFlags = statusBarPipelineFlags;
mWifiViewModelProvider = wifiViewModelProvider;
}
public DarkIconManager create(LinearLayout group) {
return new DarkIconManager(
group, mFeatureFlags, mStatusBarPipelineFlags, mWifiViewModelProvider);
}
}
}
/** */
class TintedIconManager extends IconManager {
private int mColor;
public TintedIconManager(ViewGroup group, FeatureFlags featureFlags) {
super(group, featureFlags);
public TintedIconManager(
ViewGroup group,
FeatureFlags featureFlags,
StatusBarPipelineFlags statusBarPipelineFlags,
Provider<WifiViewModel> wifiViewModelProvider) {
super(group, featureFlags, statusBarPipelineFlags, wifiViewModelProvider);
}
@Override
@@ -223,14 +258,22 @@ public interface StatusBarIconController {
@SysUISingleton
public static class Factory {
private final FeatureFlags mFeatureFlags;
private final StatusBarPipelineFlags mStatusBarPipelineFlags;
private final Provider<WifiViewModel> mWifiViewModelProvider;
@Inject
public Factory(FeatureFlags featureFlags) {
public Factory(
FeatureFlags featureFlags,
StatusBarPipelineFlags statusBarPipelineFlags,
Provider<WifiViewModel> wifiViewModelProvider) {
mFeatureFlags = featureFlags;
mStatusBarPipelineFlags = statusBarPipelineFlags;
mWifiViewModelProvider = wifiViewModelProvider;
}
public TintedIconManager create(ViewGroup group) {
return new TintedIconManager(group, mFeatureFlags);
return new TintedIconManager(
group, mFeatureFlags, mStatusBarPipelineFlags, mWifiViewModelProvider);
}
}
}
@@ -239,8 +282,10 @@ public interface StatusBarIconController {
* Turns info from StatusBarIconController into ImageViews in a ViewGroup.
*/
class IconManager implements DemoModeCommandReceiver {
private final FeatureFlags mFeatureFlags;
protected final ViewGroup mGroup;
private final FeatureFlags mFeatureFlags;
private final StatusBarPipelineFlags mStatusBarPipelineFlags;
private final Provider<WifiViewModel> mWifiViewModelProvider;
protected final Context mContext;
protected final int mIconSize;
// Whether or not these icons show up in dumpsys
@@ -254,9 +299,15 @@ public interface StatusBarIconController {
protected ArrayList<String> mBlockList = new ArrayList<>();
public IconManager(ViewGroup group, FeatureFlags featureFlags) {
mFeatureFlags = featureFlags;
public IconManager(
ViewGroup group,
FeatureFlags featureFlags,
StatusBarPipelineFlags statusBarPipelineFlags,
Provider<WifiViewModel> wifiViewModelProvider) {
mGroup = group;
mFeatureFlags = featureFlags;
mStatusBarPipelineFlags = statusBarPipelineFlags;
mWifiViewModelProvider = wifiViewModelProvider;
mContext = group.getContext();
mIconSize = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_icon_size);
@@ -308,7 +359,7 @@ public interface StatusBarIconController {
return addIcon(index, slot, blocked, holder.getIcon());
case TYPE_WIFI:
return addSignalIcon(index, slot, holder.getWifiState());
return addWifiIcon(index, slot, holder.getWifiState());
case TYPE_MOBILE:
return addMobileIcon(index, slot, holder.getMobileState());
@@ -327,9 +378,17 @@ public interface StatusBarIconController {
}
@VisibleForTesting
protected StatusBarWifiView addSignalIcon(int index, String slot, WifiIconState state) {
StatusBarWifiView view = onCreateStatusBarWifiView(slot);
view.applyWifiState(state);
protected StatusIconDisplayable addWifiIcon(int index, String slot, WifiIconState state) {
final BaseStatusBarWifiView view;
if (mStatusBarPipelineFlags.isNewPipelineFrontendEnabled()) {
view = onCreateModernStatusBarWifiView(slot);
// When [ModernStatusBarWifiView] is created, it will automatically apply the
// correct view state so we don't need to call applyWifiState.
} else {
StatusBarWifiView wifiView = onCreateStatusBarWifiView(slot);
wifiView.applyWifiState(state);
view = wifiView;
}
mGroup.addView(view, index, onCreateLayoutParams());
if (mIsInDemoMode) {
@@ -359,6 +418,11 @@ public interface StatusBarIconController {
return view;
}
private ModernStatusBarWifiView onCreateModernStatusBarWifiView(String slot) {
return ModernStatusBarWifiView.constructAndBind(
mContext, slot, mWifiViewModelProvider.get());
}
private StatusBarMobileView onCreateStatusBarMobileView(String slot) {
StatusBarMobileView view = StatusBarMobileView.fromContext(mContext, slot);
return view;
@@ -415,9 +479,8 @@ public interface StatusBarIconController {
onSetIcon(viewIndex, holder.getIcon());
return;
case TYPE_WIFI:
onSetSignalIcon(viewIndex, holder.getWifiState());
onSetWifiIcon(viewIndex, holder.getWifiState());
return;
case TYPE_MOBILE:
onSetMobileIcon(viewIndex, holder.getMobileState());
default:
@@ -425,10 +488,16 @@ public interface StatusBarIconController {
}
}
public void onSetSignalIcon(int viewIndex, WifiIconState state) {
StatusBarWifiView wifiView = (StatusBarWifiView) mGroup.getChildAt(viewIndex);
if (wifiView != null) {
wifiView.applyWifiState(state);
public void onSetWifiIcon(int viewIndex, WifiIconState state) {
View view = mGroup.getChildAt(viewIndex);
if (view instanceof StatusBarWifiView) {
((StatusBarWifiView) view).applyWifiState(state);
} else if (view instanceof ModernStatusBarWifiView) {
// ModernStatusBarWifiView will automatically apply state based on its callbacks, so
// we don't need to call applyWifiState.
} else {
throw new IllegalStateException("View at " + viewIndex + " must be of type "
+ "StatusBarWifiView or ModernStatusBarWifiView");
}
if (mIsInDemoMode) {

View File

@@ -287,6 +287,7 @@ public abstract class StatusBarViewModule {
PanelExpansionStateManager panelExpansionStateManager,
FeatureFlags featureFlags,
StatusBarIconController statusBarIconController,
StatusBarIconController.DarkIconManager.Factory darkIconManagerFactory,
StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
KeyguardStateController keyguardStateController,
NotificationPanelViewController notificationPanelViewController,
@@ -308,6 +309,7 @@ public abstract class StatusBarViewModule {
panelExpansionStateManager,
featureFlags,
statusBarIconController,
darkIconManagerFactory,
statusBarHideIconsForBouncerManager,
keyguardStateController,
notificationPanelViewController,

View File

@@ -130,6 +130,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
private final StatusBarIconController mStatusBarIconController;
private final CarrierConfigTracker mCarrierConfigTracker;
private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
private final StatusBarIconController.DarkIconManager.Factory mDarkIconManagerFactory;
private final SecureSettings mSecureSettings;
private final Executor mMainExecutor;
private final DumpManager mDumpManager;
@@ -185,6 +186,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
PanelExpansionStateManager panelExpansionStateManager,
FeatureFlags featureFlags,
StatusBarIconController statusBarIconController,
StatusBarIconController.DarkIconManager.Factory darkIconManagerFactory,
StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
KeyguardStateController keyguardStateController,
NotificationPanelViewController notificationPanelViewController,
@@ -207,6 +209,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mFeatureFlags = featureFlags;
mStatusBarIconController = statusBarIconController;
mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager;
mDarkIconManagerFactory = darkIconManagerFactory;
mKeyguardStateController = keyguardStateController;
mNotificationPanelViewController = notificationPanelViewController;
mNetworkController = networkController;
@@ -247,7 +250,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
mStatusBar.restoreHierarchyState(
savedInstanceState.getSparseParcelableArray(EXTRA_PANEL_STATE));
}
mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons), mFeatureFlags);
mDarkIconManager = mDarkIconManagerFactory.create(view.findViewById(R.id.statusIcons));
mDarkIconManager.setShouldLog(true);
updateBlockedIcons();
mStatusBarIconController.addIconGroup(mDarkIconManager);

View File

@@ -43,7 +43,7 @@ class ConnectivityInfoProcessor @Inject constructor(
private val wifiViewModelProvider: Provider<WifiViewModel>,
) : CoreStartable(context) {
override fun start() {
if (!statusBarPipelineFlags.isNewPipelineEnabled()) {
if (!statusBarPipelineFlags.isNewPipelineBackendEnabled()) {
return
}
// TODO(b/238425913): The view binder should do this instead. For now, do it here so we can

View File

@@ -25,13 +25,28 @@ import javax.inject.Inject
@SysUISingleton
class StatusBarPipelineFlags @Inject constructor(private val featureFlags: FeatureFlags) {
/**
* Returns true if we should run the new pipeline.
* Returns true if we should run the new pipeline backend.
*
* TODO(b/238425913): We may want to split this out into:
* (1) isNewPipelineLoggingEnabled(), where the new pipeline runs and logs its decisions but
* doesn't change the UI at all.
* (2) isNewPipelineEnabled(), where the new pipeline runs and does change the UI (and the old
* pipeline doesn't change the UI).
* The new pipeline backend hooks up to all our external callbacks, logs those callback inputs,
* and logs the output state.
*/
fun isNewPipelineEnabled(): Boolean = featureFlags.isEnabled(Flags.NEW_STATUS_BAR_PIPELINE)
fun isNewPipelineBackendEnabled(): Boolean =
featureFlags.isEnabled(Flags.NEW_STATUS_BAR_PIPELINE_BACKEND)
/**
* Returns true if we should run the new pipeline frontend *and* backend.
*
* The new pipeline frontend will use the outputted state from the new backend and will make the
* correct changes to the UI.
*/
fun isNewPipelineFrontendEnabled(): Boolean =
isNewPipelineBackendEnabled() &&
featureFlags.isEnabled(Flags.NEW_STATUS_BAR_PIPELINE_FRONTEND)
/**
* Returns true if we should apply some coloring to icons that were rendered with the new
* pipeline to help with debugging.
*/
// For now, just always apply the debug coloring if we've enabled frontend rendering.
fun useNewPipelineDebugColoring(): Boolean = isNewPipelineFrontendEnabled()
}

View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2022 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.pipeline.wifi.ui.binder
import android.content.res.ColorStateList
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.R
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel
import kotlinx.coroutines.InternalCoroutinesApi
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
/**
* Binds a wifi icon in the status bar to its view-model.
*
* To use this properly, users should maintain a one-to-one relationship between the [View] and the
* view-binding, binding each view only once. It is okay and expected for the same instance of the
* view-model to be reused for multiple view/view-binder bindings.
*/
@OptIn(InternalCoroutinesApi::class)
object WifiViewBinder {
/** Binds the view to the view-model, continuing to update the former based on the latter. */
@JvmStatic
fun bind(
view: ViewGroup,
viewModel: WifiViewModel,
) {
val iconView = view.requireViewById<ImageView>(R.id.wifi_signal)
view.isVisible = true
iconView.isVisible = true
iconView.setImageDrawable(view.context.getDrawable(WIFI_FULL_ICONS[2]))
view.repeatWhenAttached {
repeatOnLifecycle(Lifecycle.State.STARTED) {
launch {
viewModel.tint.collect { tint ->
iconView.imageTintList = ColorStateList.valueOf(tint)
}
}
}
}
// TODO(b/238425913): Hook up to [viewModel] to render actual changes to the wifi icon.
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2022 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.pipeline.wifi.ui.view
import android.content.Context
import android.graphics.Rect
import android.util.AttributeSet
import android.view.LayoutInflater
import com.android.systemui.R
import com.android.systemui.statusbar.BaseStatusBarWifiView
import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
import com.android.systemui.statusbar.pipeline.wifi.ui.binder.WifiViewBinder
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel
/**
* A new and more modern implementation of [com.android.systemui.statusbar.StatusBarWifiView] that
* is updated by [WifiViewBinder].
*/
class ModernStatusBarWifiView(
context: Context,
attrs: AttributeSet?
) : BaseStatusBarWifiView(context, attrs) {
private lateinit var slot: String
override fun onDarkChanged(areas: ArrayList<Rect>?, darkIntensity: Float, tint: Int) {
// TODO(b/238425913)
}
override fun getSlot() = slot
override fun setStaticDrawableColor(color: Int) {
// TODO(b/238425913)
}
override fun setDecorColor(color: Int) {
// TODO(b/238425913)
}
override fun setVisibleState(state: Int, animate: Boolean) {
// TODO(b/238425913)
}
override fun getVisibleState(): Int {
// TODO(b/238425913)
return STATE_ICON
}
override fun isIconVisible(): Boolean {
// TODO(b/238425913)
return true
}
/** Set the slot name for this view. */
private fun setSlot(slotName: String) {
this.slot = slotName
}
companion object {
/**
* Inflates a new instance of [ModernStatusBarWifiView], binds it to [viewModel], and
* returns it.
*/
@JvmStatic
fun constructAndBind(
context: Context,
slot: String,
viewModel: WifiViewModel,
): ModernStatusBarWifiView {
return (
LayoutInflater.from(context).inflate(R.layout.new_status_bar_wifi_group, null)
as ModernStatusBarWifiView
).also {
it.setSlot(slot)
WifiViewBinder.bind(it, viewModel)
}
}
}
}

View File

@@ -16,12 +16,15 @@
package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
import android.graphics.Color
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flowOf
/**
@@ -30,9 +33,10 @@ import kotlinx.coroutines.flow.flowOf
* TODO(b/238425913): Hook this up to the real status bar wifi view using a view binder.
*/
class WifiViewModel @Inject constructor(
private val constants: WifiConstants,
private val logger: ConnectivityPipelineLogger,
private val interactor: WifiInteractor,
statusBarPipelineFlags: StatusBarPipelineFlags,
private val constants: WifiConstants,
private val logger: ConnectivityPipelineLogger,
private val interactor: WifiInteractor,
) {
val isActivityInVisible: Flow<Boolean>
get() =
@@ -42,4 +46,11 @@ class WifiViewModel @Inject constructor(
interactor.hasActivityIn
}
.logOutputChange(logger, "activityInVisible")
/** The tint that should be applied to the icon. */
val tint: Flow<Int> = if (!statusBarPipelineFlags.useNewPipelineDebugColoring()) {
emptyFlow()
} else {
flowOf(Color.CYAN)
}
}

View File

@@ -93,6 +93,10 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
private lateinit var featureFlags: FeatureFlags
@Mock
private lateinit var insetsProvider: StatusBarContentInsetsProvider
@Mock
private lateinit var iconManagerFactory: StatusBarIconController.TintedIconManager.Factory
@Mock
private lateinit var iconManager: StatusBarIconController.TintedIconManager
private val qsExpansionPathInterpolator = QSExpansionPathInterpolator()
@@ -106,6 +110,7 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
`when`(qsCarrierGroupControllerBuilder.build()).thenReturn(qsCarrierGroupController)
`when`(variableDateViewControllerFactory.create(any()))
.thenReturn(variableDateViewController)
`when`(iconManagerFactory.create(any())).thenReturn(iconManager)
`when`(view.resources).thenReturn(mContext.resources)
`when`(view.isAttachedToWindow).thenReturn(true)
`when`(view.context).thenReturn(context)
@@ -122,7 +127,8 @@ class QuickStatusBarHeaderControllerTest : SysuiTestCase() {
featureFlags,
variableDateViewControllerFactory,
batteryMeterViewController,
insetsProvider
insetsProvider,
iconManagerFactory,
)
}

View File

@@ -91,6 +91,10 @@ class LargeScreenShadeHeaderControllerCombinedTest : SysuiTestCase() {
@Mock
private lateinit var statusBarIconController: StatusBarIconController
@Mock
private lateinit var iconManagerFactory: StatusBarIconController.TintedIconManager.Factory
@Mock
private lateinit var iconManager: StatusBarIconController.TintedIconManager
@Mock
private lateinit var qsCarrierGroupController: QSCarrierGroupController
@Mock
private lateinit var qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder
@@ -169,6 +173,8 @@ class LargeScreenShadeHeaderControllerCombinedTest : SysuiTestCase() {
}
whenever(view.visibility).thenAnswer { _ -> viewVisibility }
whenever(iconManagerFactory.create(any())).thenReturn(iconManager)
whenever(featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)).thenReturn(true)
whenever(featureFlags.isEnabled(Flags.NEW_HEADER)).thenReturn(true)
@@ -178,6 +184,7 @@ class LargeScreenShadeHeaderControllerCombinedTest : SysuiTestCase() {
controller = LargeScreenShadeHeaderController(
view,
statusBarIconController,
iconManagerFactory,
privacyIconsController,
insetsProvider,
configurationController,

View File

@@ -43,6 +43,8 @@ class LargeScreenShadeHeaderControllerTest : SysuiTestCase() {
@Mock private lateinit var view: View
@Mock private lateinit var statusIcons: StatusIconContainer
@Mock private lateinit var statusBarIconController: StatusBarIconController
@Mock private lateinit var iconManagerFactory: StatusBarIconController.TintedIconManager.Factory
@Mock private lateinit var iconManager: StatusBarIconController.TintedIconManager
@Mock private lateinit var qsCarrierGroupController: QSCarrierGroupController
@Mock private lateinit var qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder
@Mock private lateinit var featureFlags: FeatureFlags
@@ -91,10 +93,12 @@ class LargeScreenShadeHeaderControllerTest : SysuiTestCase() {
whenever(view.visibility).thenAnswer { _ -> viewVisibility }
whenever(variableDateViewControllerFactory.create(any()))
.thenReturn(variableDateViewController)
whenever(iconManagerFactory.create(any())).thenReturn(iconManager)
whenever(featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)).thenReturn(false)
mLargeScreenShadeHeaderController = LargeScreenShadeHeaderController(
view,
statusBarIconController,
iconManagerFactory,
privacyIconsController,
insetsProvider,
configurationController,

View File

@@ -47,7 +47,6 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shade.NotificationPanelViewController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -89,7 +88,9 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
@Mock
private StatusBarIconController mStatusBarIconController;
@Mock
private FeatureFlags mFeatureFlags;
private StatusBarIconController.TintedIconManager.Factory mIconManagerFactory;
@Mock
private StatusBarIconController.TintedIconManager mIconManager;
@Mock
private BatteryMeterViewController mBatteryMeterViewController;
@Mock
@@ -129,6 +130,8 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
when(mIconManagerFactory.create(any())).thenReturn(mIconManager);
allowTestableLooperAsMainThread();
TestableLooper.get(this).runWithLooper(() -> {
mKeyguardStatusBarView =
@@ -148,7 +151,7 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
mBatteryController,
mUserInfoController,
mStatusBarIconController,
new StatusBarIconController.TintedIconManager.Factory(mFeatureFlags),
mIconManagerFactory,
mBatteryMeterViewController,
mNotificationPanelViewStateProvider,
mKeyguardStateController,

View File

@@ -40,12 +40,16 @@ import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconMana
import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.MobileIconState;
import com.android.systemui.statusbar.phone.StatusBarSignalPolicy.WifiIconState;
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags;
import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel;
import com.android.systemui.utils.leaks.LeakCheckedTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import javax.inject.Provider;
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@SmallTest
@@ -67,7 +71,11 @@ public class StatusBarIconControllerTest extends LeakCheckedTest {
@Test
public void testSetCalledOnAdd_DarkIconManager() {
LinearLayout layout = new LinearLayout(mContext);
TestDarkIconManager manager = new TestDarkIconManager(layout, mock(FeatureFlags.class));
TestDarkIconManager manager = new TestDarkIconManager(
layout,
mock(FeatureFlags.class),
mock(StatusBarPipelineFlags.class),
() -> mock(WifiViewModel.class));
testCallOnAdd_forManager(manager);
}
@@ -104,8 +112,12 @@ public class StatusBarIconControllerTest extends LeakCheckedTest {
private static class TestDarkIconManager extends DarkIconManager
implements TestableIconManager {
TestDarkIconManager(LinearLayout group, FeatureFlags featureFlags) {
super(group, featureFlags);
TestDarkIconManager(
LinearLayout group,
FeatureFlags featureFlags,
StatusBarPipelineFlags statusBarPipelineFlags,
Provider<WifiViewModel> wifiViewModelProvider) {
super(group, featureFlags, statusBarPipelineFlags, wifiViewModelProvider);
}
@Override
@@ -123,7 +135,7 @@ public class StatusBarIconControllerTest extends LeakCheckedTest {
}
@Override
protected StatusBarWifiView addSignalIcon(int index, String slot, WifiIconState state) {
protected StatusBarWifiView addWifiIcon(int index, String slot, WifiIconState state) {
StatusBarWifiView mock = mock(StatusBarWifiView.class);
mGroup.addView(mock, index);
return mock;
@@ -140,7 +152,10 @@ public class StatusBarIconControllerTest extends LeakCheckedTest {
private static class TestIconManager extends IconManager implements TestableIconManager {
TestIconManager(ViewGroup group) {
super(group, mock(FeatureFlags.class));
super(group,
mock(FeatureFlags.class),
mock(StatusBarPipelineFlags.class),
() -> mock(WifiViewModel.class));
}
@Override
@@ -158,7 +173,7 @@ public class StatusBarIconControllerTest extends LeakCheckedTest {
}
@Override
protected StatusBarWifiView addSignalIcon(int index, String slot, WifiIconState state) {
protected StatusBarWifiView addWifiIcon(int index, String slot, WifiIconState state) {
StatusBarWifiView mock = mock(StatusBarWifiView.class);
mGroup.addView(mock, index);
return mock;

View File

@@ -113,6 +113,10 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
@Mock
private NotificationPanelViewController mNotificationPanelViewController;
@Mock
private StatusBarIconController.DarkIconManager.Factory mIconManagerFactory;
@Mock
private StatusBarIconController.DarkIconManager mIconManager;
@Mock
private StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
@Mock
private DumpManager mDumpManager;
@@ -463,6 +467,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
mOperatorNameViewControllerFactory = mock(OperatorNameViewController.Factory.class);
when(mOperatorNameViewControllerFactory.create(any()))
.thenReturn(mOperatorNameViewController);
when(mIconManagerFactory.create(any())).thenReturn(mIconManager);
mSecureSettings = mock(SecureSettings.class);
setUpNotificationIconAreaController();
@@ -475,6 +480,7 @@ public class CollapsedStatusBarFragmentTest extends SysuiBaseFragmentTest {
new PanelExpansionStateManager(),
mock(FeatureFlags.class),
mStatusBarIconController,
mIconManagerFactory,
mStatusBarHideIconsForBouncerManager,
mKeyguardStateController,
mNotificationPanelViewController,

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2022 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.pipeline.wifi.ui.view
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.lifecycle.InstantTaskExecutorRule
import com.android.systemui.util.Assert
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
@SmallTest
@RunWith(JUnit4::class)
@RunWithLooper
class ModernStatusBarWifiViewTest : SysuiTestCase() {
@JvmField @Rule
val instantTaskExecutor = InstantTaskExecutorRule()
@Before
fun setUp() {
Assert.setTestThread(Thread.currentThread())
}
@Test
fun constructAndBind_hasCorrectSlot() {
val view = ModernStatusBarWifiView.constructAndBind(
context, "slotName", mock()
)
assertThat(view.slot).isEqualTo("slotName")
}
}

View File

@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
@@ -43,6 +44,7 @@ class WifiViewModelTest : SysuiTestCase() {
private lateinit var underTest: WifiViewModel
@Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
@Mock private lateinit var logger: ConnectivityPipelineLogger
@Mock private lateinit var constants: WifiConstants
private lateinit var repository: FakeWifiRepository
@@ -55,9 +57,10 @@ class WifiViewModelTest : SysuiTestCase() {
interactor = WifiInteractor(repository)
underTest = WifiViewModel(
constants,
logger,
interactor
statusBarPipelineFlags,
constants,
logger,
interactor
)
// Set up with a valid SSID