diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 63af3e0c9f307..c6452c03459ab 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -21,6 +21,8 @@
-
+ android:layout_height="wrap_content" />
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 29a8da0d421c4..69e38745f23b9 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -16,18 +16,29 @@
package com.android.systemui;
import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.Rect;
import android.util.ArraySet;
import android.util.AttributeSet;
+import android.util.TypedValue;
import android.view.View;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerService.Tunable;
public class BatteryMeterView extends ImageView implements
- BatteryController.BatteryStateChangeCallback, TunerService.Tunable {
+ BatteryStateChangeCallback, Tunable, DarkReceiver, ConfigurationListener {
private final BatteryMeterDrawable mDrawable;
private final String mSlotBattery;
@@ -77,6 +88,7 @@ public class BatteryMeterView extends ImageView implements
mBatteryController.addCallback(this);
mDrawable.startListening();
Dependency.get(TunerService.class).addTunable(this, StatusBarIconController.ICON_BLACKLIST);
+ Dependency.get(ConfigurationController.class).addCallback(this);
}
@Override
@@ -85,6 +97,7 @@ public class BatteryMeterView extends ImageView implements
mBatteryController.removeCallback(this);
mDrawable.stopListening();
Dependency.get(TunerService.class).removeTunable(this);
+ Dependency.get(ConfigurationController.class).removeCallback(this);
}
@Override
@@ -99,8 +112,35 @@ public class BatteryMeterView extends ImageView implements
}
- public void setDarkIntensity(float f) {
- mDrawable.setDarkIntensity(f);
+ @Override
+ public void onDensityOrFontScaleChanged() {
+ scaleBatteryMeterViews();
+ }
+
+ /**
+ * Looks up the scale factor for status bar icons and scales the battery view by that amount.
+ */
+ private void scaleBatteryMeterViews() {
+ Resources res = getContext().getResources();
+ TypedValue typedValue = new TypedValue();
+
+ res.getValue(R.dimen.status_bar_icon_scale_factor, typedValue, true);
+ float iconScaleFactor = typedValue.getFloat();
+
+ int batteryHeight = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_height);
+ int batteryWidth = res.getDimensionPixelSize(R.dimen.status_bar_battery_icon_width);
+ int marginBottom = res.getDimensionPixelSize(R.dimen.battery_margin_bottom);
+
+ LinearLayout.LayoutParams scaledLayoutParams = new LinearLayout.LayoutParams(
+ (int) (batteryWidth * iconScaleFactor), (int) (batteryHeight * iconScaleFactor));
+ scaledLayoutParams.setMarginsRelative(0, 0, 0, marginBottom);
+
+ setLayoutParams(scaledLayoutParams);
+ }
+
+ @Override
+ public void onDarkChanged(Rect area, float darkIntensity, int tint) {
+ mDrawable.setDarkIntensity(DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0);
}
public void setRawColors(int fgColor, int bgColor) {
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 7066a1b7ca255..1d4a0939c16b7 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -25,9 +25,13 @@ import android.util.ArrayMap;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.assist.AssistManager;
import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
+import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
import com.android.systemui.statusbar.phone.ManagedProfileController;
import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarWindowManager;
+import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.BatteryControllerImpl;
@@ -35,6 +39,8 @@ import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.CastControllerImpl;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
import com.android.systemui.statusbar.policy.DataSaverController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
@@ -187,6 +193,15 @@ public class Dependency extends SystemUI {
mProviders.put(StatusBarWindowManager.class.getName(), () ->
new StatusBarWindowManager(mContext));
+ mProviders.put(DarkIconDispatcher.class.getName(), () ->
+ new DarkIconDispatcherImpl(mContext));
+
+ mProviders.put(ConfigurationController.class.getName(), () ->
+ new ConfigurationControllerImpl(mContext));
+
+ mProviders.put(StatusBarIconController.class.getName(), () ->
+ new StatusBarIconControllerImpl(mContext));
+
// Put all dependencies above here so the factory can override them if it wants.
SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
}
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
index 50506a95851c8..0c6bf52e84ba3 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -97,7 +97,7 @@ public class FragmentHostManager {
return p;
}
- public void addTagListener(String tag, FragmentListener listener) {
+ public FragmentHostManager addTagListener(String tag, FragmentListener listener) {
ArrayList listeners = mListeners.get(tag);
if (listeners == null) {
listeners = new ArrayList<>();
@@ -108,6 +108,7 @@ public class FragmentHostManager {
if (current != null && current.getView() != null) {
listener.onFragmentViewCreated(tag, current);
}
+ return this;
}
// Shouldn't generally be needed, included for completeness sake.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index a4cd14d779260..b48b829d14f77 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -179,7 +179,7 @@ public class CastTile extends QSTile {
}
@Override
- public void onKeyguardChanged() {
+ public void onKeyguardShowingChanged() {
refreshState();
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 5374f18d1ad9f..423a1df703e19 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -141,7 +141,7 @@ public class LocationTile extends QSTile {
}
@Override
- public void onKeyguardChanged() {
+ public void onKeyguardShowingChanged() {
refreshState();
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 9245df0ff5fcc..5366da1122758 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -25,7 +25,6 @@ import android.os.Looper;
import android.os.Message;
import android.support.annotation.VisibleForTesting;
import android.util.Pair;
-import android.view.KeyEvent;
import com.android.internal.os.SomeArgs;
import com.android.internal.statusbar.IStatusBar;
@@ -92,6 +91,8 @@ public class CommandQueue extends IStatusBar.Stub {
private final Object mLock = new Object();
private ArrayList mCallbacks = new ArrayList<>();
private Handler mHandler = new H(Looper.getMainLooper());
+ private int mDisable1;
+ private int mDisable2;
/**
* These methods are called back on the main thread.
@@ -119,9 +120,9 @@ public class CommandQueue extends IStatusBar.Stub {
default void cancelPreloadRecentApps() { }
default void setWindowState(int window, int state) { }
default void showScreenPinningRequest(int taskId) { }
- default void appTransitionPending() { }
+ default void appTransitionPending(boolean forced) { }
default void appTransitionCancelled() { }
- default void appTransitionStarting(long startTime, long duration) { }
+ default void appTransitionStarting(long startTime, long duration, boolean forced) { }
default void appTransitionFinished() { }
default void showAssistDisclosure() { }
default void startAssist(Bundle args) { }
@@ -141,6 +142,7 @@ public class CommandQueue extends IStatusBar.Stub {
public void addCallbacks(Callbacks callbacks) {
mCallbacks.add(callbacks);
+ callbacks.disable(mDisable1, mDisable2, false /* animate */);
}
public void removeCallbacks(Callbacks callbacks) {
@@ -164,6 +166,8 @@ public class CommandQueue extends IStatusBar.Stub {
public void disable(int state1, int state2) {
synchronized (mLock) {
+ mDisable1 = state1;
+ mDisable2 = state2;
mHandler.removeMessages(MSG_DISABLE);
mHandler.obtainMessage(MSG_DISABLE, state1, state2, null).sendToTarget();
}
@@ -315,9 +319,13 @@ public class CommandQueue extends IStatusBar.Stub {
}
public void appTransitionPending() {
+ appTransitionPending(false /* forced */);
+ }
+
+ public void appTransitionPending(boolean forced) {
synchronized (mLock) {
mHandler.removeMessages(MSG_APP_TRANSITION_PENDING);
- mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING);
+ mHandler.obtainMessage(MSG_APP_TRANSITION_PENDING, forced ? 1 : 0, 0).sendToTarget();
}
}
@@ -329,10 +337,14 @@ public class CommandQueue extends IStatusBar.Stub {
}
public void appTransitionStarting(long startTime, long duration) {
+ appTransitionStarting(startTime, duration, false /* forced */);
+ }
+
+ public void appTransitionStarting(long startTime, long duration, boolean forced) {
synchronized (mLock) {
mHandler.removeMessages(MSG_APP_TRANSITION_STARTING);
- mHandler.obtainMessage(MSG_APP_TRANSITION_STARTING, Pair.create(startTime, duration))
- .sendToTarget();
+ mHandler.obtainMessage(MSG_APP_TRANSITION_STARTING, forced ? 1 : 0, 0,
+ Pair.create(startTime, duration)).sendToTarget();
}
}
@@ -505,7 +517,7 @@ public class CommandQueue extends IStatusBar.Stub {
break;
case MSG_APP_TRANSITION_PENDING:
for (int i = 0; i < mCallbacks.size(); i++) {
- mCallbacks.get(i).appTransitionPending();
+ mCallbacks.get(i).appTransitionPending(msg.arg1 != 0);
}
break;
case MSG_APP_TRANSITION_CANCELLED:
@@ -516,7 +528,8 @@ public class CommandQueue extends IStatusBar.Stub {
case MSG_APP_TRANSITION_STARTING:
for (int i = 0; i < mCallbacks.size(); i++) {
Pair data = (Pair) msg.obj;
- mCallbacks.get(i).appTransitionStarting(data.first, data.second);
+ mCallbacks.get(i).appTransitionStarting(data.first, data.second,
+ msg.arg1 != 0);
}
break;
case MSG_APP_TRANSITION_FINISHED:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 45eb5df43a06b..89041f9695ead 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -43,6 +43,8 @@ import android.widget.LinearLayout;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
import com.android.systemui.statusbar.policy.NetworkControllerImpl;
@@ -54,10 +56,9 @@ import java.util.ArrayList;
import java.util.List;
// Intimately tied to the design of res/layout/signal_cluster_view.xml
-public class SignalClusterView
- extends LinearLayout
- implements NetworkControllerImpl.SignalCallback,
- SecurityController.SecurityControllerCallback, Tunable {
+public class SignalClusterView extends LinearLayout implements NetworkControllerImpl.SignalCallback,
+ SecurityController.SecurityControllerCallback, Tunable,
+ DarkReceiver {
static final String TAG = "SignalClusterView";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -581,7 +582,8 @@ public class SignalClusterView
return colorAccent;
}
- public void setIconTint(int tint, float darkIntensity, Rect tintArea) {
+ @Override
+ public void onDarkChanged(Rect tintArea, float darkIntensity, int tint) {
boolean changed = tint != mIconTint || darkIntensity != mDarkIntensity
|| !mTintArea.equals(tintArea);
mIconTint = tint;
@@ -593,16 +595,16 @@ public class SignalClusterView
}
private void applyIconTint() {
- setTint(mVpn, StatusBarIconController.getTint(mTintArea, mVpn, mIconTint));
- setTint(mAirplane, StatusBarIconController.getTint(mTintArea, mAirplane, mIconTint));
+ setTint(mVpn, DarkIconDispatcher.getTint(mTintArea, mVpn, mIconTint));
+ setTint(mAirplane, DarkIconDispatcher.getTint(mTintArea, mAirplane, mIconTint));
applyDarkIntensity(
- StatusBarIconController.getDarkIntensity(mTintArea, mNoSims, mDarkIntensity),
+ DarkIconDispatcher.getDarkIntensity(mTintArea, mNoSims, mDarkIntensity),
mNoSims, mNoSimsDark);
applyDarkIntensity(
- StatusBarIconController.getDarkIntensity(mTintArea, mWifi, mDarkIntensity),
+ DarkIconDispatcher.getDarkIntensity(mTintArea, mWifi, mDarkIntensity),
mWifi, mWifiDark);
applyDarkIntensity(
- StatusBarIconController.getDarkIntensity(mTintArea, mEthernet, mDarkIntensity),
+ DarkIconDispatcher.getDarkIntensity(mTintArea, mEthernet, mDarkIntensity),
mEthernet, mEthernetDark);
for (int i = 0; i < mPhoneStates.size(); i++) {
mPhoneStates.get(i).setIconTint(mIconTint, mDarkIntensity, mTintArea);
@@ -740,10 +742,10 @@ public class SignalClusterView
public void setIconTint(int tint, float darkIntensity, Rect tintArea) {
applyDarkIntensity(
- StatusBarIconController.getDarkIntensity(tintArea, mMobile, darkIntensity),
+ DarkIconDispatcher.getDarkIntensity(tintArea, mMobile, darkIntensity),
mMobile, mMobileDark);
- setTint(mMobileType, StatusBarIconController.getTint(tintArea, mMobileType, tint));
- setTint(mMobileRoaming, StatusBarIconController.getTint(tintArea, mMobileRoaming,
+ setTint(mMobileType, DarkIconDispatcher.getTint(tintArea, mMobileType, tint));
+ setTint(mMobileRoaming, DarkIconDispatcher.getTint(tintArea, mMobileRoaming,
tint));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 41613894252a4..f53dad5484a2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -32,17 +32,19 @@ import android.view.ViewGroup.LayoutParams;
import android.view.ViewStub;
import android.view.WindowManager;
import android.widget.LinearLayout;
+
import com.android.systemui.BatteryMeterView;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
+import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment;
import com.android.systemui.statusbar.phone.NavigationBarView;
import com.android.systemui.statusbar.phone.StatusBar;
-import com.android.systemui.statusbar.phone.PhoneStatusBarView;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -75,7 +77,6 @@ public class CarStatusBar extends StatusBar implements
createBatteryController();
mCarBatteryController.startListening();
- mConnectedDeviceSignalController.startListening();
}
@Override
@@ -87,32 +88,40 @@ public class CarStatusBar extends StatusBar implements
}
@Override
- protected PhoneStatusBarView makeStatusBarView() {
- PhoneStatusBarView statusBarView = super.makeStatusBarView();
+ protected void makeStatusBarView() {
+ super.makeStatusBarView();
- mBatteryMeterView = ((BatteryMeterView) statusBarView.findViewById(R.id.battery));
+ FragmentHostManager manager = FragmentHostManager.get(mStatusBarWindow);
+ manager.addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
+ mBatteryMeterView = ((BatteryMeterView) fragment.getView().findViewById(
+ R.id.battery));
- // By default, the BatteryMeterView should not be visible. It will be toggled visible
- // when a device has connected by bluetooth.
- mBatteryMeterView.setVisibility(View.GONE);
+ // By default, the BatteryMeterView should not be visible. It will be toggled
+ // when a device has connected by bluetooth.
+ mBatteryMeterView.setVisibility(View.GONE);
- ViewStub stub = (ViewStub) statusBarView.findViewById(R.id.connected_device_signals_stub);
- View signalsView = stub.inflate();
+ ViewStub stub = (ViewStub) fragment.getView().findViewById(
+ R.id.connected_device_signals_stub);
+ View signalsView = stub.inflate();
- // When a ViewStub if inflated, it does not respect the margins on the inflated view.
- // As a result, manually add the ending margin.
- ((LinearLayout.LayoutParams) signalsView.getLayoutParams()).setMarginEnd(
- mContext.getResources().getDimensionPixelOffset(
- R.dimen.status_bar_connected_device_signal_margin_end));
+ // When a ViewStub if inflated, it does not respect the margins on the
+ // inflated view.
+ // As a result, manually add the ending margin.
+ ((LinearLayout.LayoutParams) signalsView.getLayoutParams()).setMarginEnd(
+ mContext.getResources().getDimensionPixelOffset(
+ R.dimen.status_bar_connected_device_signal_margin_end));
- mConnectedDeviceSignalController = new ConnectedDeviceSignalController(mContext,
- signalsView);
+ if (mConnectedDeviceSignalController != null) {
+ mConnectedDeviceSignalController.stopListening();
+ }
+ mConnectedDeviceSignalController = new ConnectedDeviceSignalController(mContext,
+ signalsView);
+ mConnectedDeviceSignalController.startListening();
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "makeStatusBarView(). mBatteryMeterView: " + mBatteryMeterView);
- }
-
- return statusBarView;
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "makeStatusBarView(). mBatteryMeterView: " + mBatteryMeterView);
+ }
+ });
}
private BatteryController createBatteryController() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
new file mode 100644
index 0000000000000..1f56c563bef75
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2017 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.phone;
+
+import static com.android.systemui.statusbar.phone.StatusBar.reinflateSignalCluster;
+
+import android.annotation.Nullable;
+import android.app.Fragment;
+import android.app.StatusBarManager;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import com.android.systemui.Dependency;
+import com.android.systemui.Interpolators;
+import com.android.systemui.R;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.SignalClusterView;
+import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+import com.android.systemui.statusbar.policy.EncryptionHelper;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.NetworkController;
+
+/**
+ * Contains the collapsed status bar and handles hiding/showing based on disable flags
+ * and keyguard state. Also manages lifecycle to make sure the views it contains are being
+ * updated by the StatusBarIconController and DarkIconManager while it is attached.
+ */
+public class CollapsedStatusBarFragment extends Fragment implements CommandQueue.Callbacks {
+
+ public static final String TAG = "CollapsedStatusBarFragment";
+ private PhoneStatusBarView mStatusBar;
+ private KeyguardMonitor mKeyguardMonitor;
+ private NetworkController mNetworkController;
+ private LinearLayout mSystemIconArea;
+ private View mNotificationIconAreaInner;
+ private int mDisabled1;
+ private StatusBar mStatusBarComponent;
+ private DarkIconManager mDarkIconManager;
+ private SignalClusterView mSignalClusterView;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
+ mNetworkController = Dependency.get(NetworkController.class);
+ mStatusBarComponent = SysUiServiceProvider.getComponent(getContext(), StatusBar.class);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.status_bar, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ mStatusBar = (PhoneStatusBarView) view;
+ mDarkIconManager = new DarkIconManager((LinearLayout) view.findViewById(R.id.statusIcons));
+ Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager);
+ mSystemIconArea = (LinearLayout) mStatusBar.findViewById(R.id.system_icon_area);
+ mSignalClusterView = reinflateSignalCluster(mStatusBar);
+ Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mSignalClusterView);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).removeCallbacks(this);
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mSignalClusterView);
+ Dependency.get(StatusBarIconController.class).removeIconGroup(mDarkIconManager);
+ }
+
+ public void initNotificationIconArea(NotificationIconAreaController
+ notificationIconAreaController) {
+ ViewGroup notificationIconArea = (ViewGroup) mStatusBar
+ .findViewById(R.id.notification_icon_area);
+ mNotificationIconAreaInner =
+ notificationIconAreaController.getNotificationInnerAreaView();
+ if (mNotificationIconAreaInner.getParent() != null) {
+ ((ViewGroup) mNotificationIconAreaInner.getParent())
+ .removeView(mNotificationIconAreaInner);
+ }
+ notificationIconArea.addView(mNotificationIconAreaInner);
+ }
+
+ @Override
+ public void disable(int state1, int state2, boolean animate) {
+ state1 = adjustDisableFlags(state1);
+ final int old1 = mDisabled1;
+ final int diff1 = state1 ^ old1;
+ mDisabled1 = state1;
+ if ((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
+ if ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) {
+ hideSystemIconArea(animate);
+ } else {
+ showSystemIconArea(animate);
+ }
+ }
+ if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+ if ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
+ hideNotificationIconArea(animate);
+ } else {
+ showNotificationIconArea(animate);
+ }
+ }
+ }
+
+ protected int adjustDisableFlags(int state) {
+ if (!mStatusBarComponent.isLaunchTransitionFadingAway()
+ && !mKeyguardMonitor.isKeyguardFadingAway()
+ && shouldHideNotificationIcons()) {
+ state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
+ state |= StatusBarManager.DISABLE_SYSTEM_INFO;
+ }
+ if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) {
+ if (mNetworkController.hasEmergencyCryptKeeperText()) {
+ state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
+ }
+ if (!mNetworkController.isRadioOn()) {
+ state |= StatusBarManager.DISABLE_SYSTEM_INFO;
+ }
+ }
+ return state;
+ }
+
+ private boolean shouldHideNotificationIcons() {
+ return !mStatusBar.isClosed() && mStatusBarComponent.shouldHideNotificationIcons();
+ }
+
+ public void hideSystemIconArea(boolean animate) {
+ animateHide(mSystemIconArea, animate);
+ }
+
+ public void showSystemIconArea(boolean animate) {
+ animateShow(mSystemIconArea, animate);
+ }
+
+ public void hideNotificationIconArea(boolean animate) {
+ animateHide(mNotificationIconAreaInner, animate);
+ }
+
+ public void showNotificationIconArea(boolean animate) {
+ animateShow(mNotificationIconAreaInner, animate);
+ }
+
+ /**
+ * Hides a view.
+ */
+ private void animateHide(final View v, boolean animate) {
+ v.animate().cancel();
+ if (!animate) {
+ v.setAlpha(0f);
+ v.setVisibility(View.INVISIBLE);
+ return;
+ }
+ v.animate()
+ .alpha(0f)
+ .setDuration(160)
+ .setStartDelay(0)
+ .setInterpolator(Interpolators.ALPHA_OUT)
+ .withEndAction(() -> v.setVisibility(View.INVISIBLE));
+ }
+
+ /**
+ * Shows a view, and synchronizes the animation with Keyguard exit animations, if applicable.
+ */
+ private void animateShow(View v, boolean animate) {
+ v.animate().cancel();
+ v.setVisibility(View.VISIBLE);
+ if (!animate) {
+ v.setAlpha(1f);
+ return;
+ }
+ v.animate()
+ .alpha(1f)
+ .setDuration(320)
+ .setInterpolator(Interpolators.ALPHA_IN)
+ .setStartDelay(50)
+
+ // We need to clean up any pending end action from animateHide if we call
+ // both hide and show in the same frame before the animation actually gets started.
+ // cancel() doesn't really remove the end action.
+ .withEndAction(null);
+
+ // Synchronize the motion with the Keyguard fading if necessary.
+ if (mKeyguardMonitor.isKeyguardFadingAway()) {
+ v.animate()
+ .setDuration(mKeyguardMonitor.getKeyguardFadingAwayDuration())
+ .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
+ .setStartDelay(mKeyguardMonitor.getKeyguardFadingAwayDelay())
+ .start();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java
new file mode 100644
index 0000000000000..020dc253da667
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 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.phone;
+
+import android.content.Context;
+import android.content.res.Configuration;
+
+import com.android.systemui.ConfigurationChangedReceiver;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+
+import java.util.ArrayList;
+
+public class ConfigurationControllerImpl implements ConfigurationController,
+ ConfigurationChangedReceiver {
+
+ private final ArrayList mListeners = new ArrayList<>();
+ private int mDensity;
+ private float mFontScale;
+
+ public ConfigurationControllerImpl(Context context) {
+ Configuration currentConfig = context.getResources().getConfiguration();
+ mFontScale = currentConfig.fontScale;
+ mDensity = currentConfig.densityDpi;
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ mListeners.forEach(l -> l.onConfigChanged(newConfig));
+ final float fontScale = newConfig.fontScale;
+ final int density = newConfig.densityDpi;
+ if (density != mDensity || mFontScale != fontScale) {
+ mListeners.forEach(l -> l.onDensityOrFontScaleChanged());
+ mDensity = density;
+ mFontScale = fontScale;
+ }
+ }
+
+ @Override
+ public void addCallback(ConfigurationListener listener) {
+ mListeners.add(listener);
+ listener.onDensityOrFontScaleChanged();
+ }
+
+ @Override
+ public void removeCallback(ConfigurationListener listener) {
+ mListeners.remove(listener);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
new file mode 100644
index 0000000000000..3f9ae80231490
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 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.phone;
+
+import static com.android.systemui.statusbar.policy.DarkIconDispatcher.getTint;
+
+import android.animation.ArgbEvaluator;
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Rect;
+import android.util.ArrayMap;
+import android.widget.ImageView;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher;
+
+public class DarkIconDispatcherImpl implements DarkIconDispatcher {
+
+ private final LightBarTransitionsController mTransitionsController;
+ private final Rect mTintArea = new Rect();
+ private final ArrayMap