From aa573e9e8632552d1fa8bdd6b0ee408ff9a93a6b Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Fri, 27 Jan 2017 17:00:29 -0500 Subject: [PATCH] Work on separating out the status bar management Lots of stuff: - Make StatusBarIconController be a permanent dependency - Break out dark stuff into DarkIconDispatcher - Create StatusBarFragment - This bit is a bit ugly for now, but will be better later - Other stuff probably Test: runtest systemui Change-Id: I4973bc9f944e66af92731bf1edd2b39657f1782f --- packages/SystemUI/res/layout/status_bar.xml | 2 + .../SystemUI/res/layout/super_status_bar.xml | 5 +- .../android/systemui/BatteryMeterView.java | 46 +- .../src/com/android/systemui/Dependency.java | 15 + .../fragments/FragmentHostManager.java | 3 +- .../android/systemui/qs/tiles/CastTile.java | 2 +- .../systemui/qs/tiles/LocationTile.java | 2 +- .../systemui/statusbar/CommandQueue.java | 29 +- .../systemui/statusbar/SignalClusterView.java | 28 +- .../systemui/statusbar/car/CarStatusBar.java | 53 +- .../phone/CollapsedStatusBarFragment.java | 223 +++++++ .../phone/ConfigurationControllerImpl.java | 60 ++ .../phone/DarkIconDispatcherImpl.java | 106 +++ .../statusbar/phone/LightBarController.java | 7 +- .../phone/LightBarTransitionsController.java | 32 +- .../phone/NavigationBarFragment.java | 31 +- .../phone/NavigationBarTransitions.java | 3 +- .../phone/NotificationIconAreaController.java | 26 +- .../systemui/statusbar/phone/PanelBar.java | 4 + .../statusbar/phone/PhoneStatusBarPolicy.java | 67 +- .../statusbar/phone/PhoneStatusBarView.java | 19 + .../statusbar/phone/QuickStatusBarHeader.java | 2 +- .../systemui/statusbar/phone/StatusBar.java | 277 +++----- .../phone/StatusBarIconController.java | 610 ++++-------------- .../phone/StatusBarIconControllerImpl.java | 230 +++++++ .../statusbar/phone/StatusBarIconList.java | 4 +- .../systemui/statusbar/policy/Clock.java | 65 +- .../policy/ConfigurationController.java | 31 + .../statusbar/policy/DarkIconDispatcher.java | 92 +++ .../statusbar/policy/KeyguardMonitor.java | 6 +- .../statusbar/policy/KeyguardMonitorImpl.java | 47 +- .../policy/UserSwitcherController.java | 2 +- .../statusbar/policy/ZenModeController.java | 16 +- .../android/systemui/tuner/TunerService.java | 3 + packages/SystemUI/tests/AndroidManifest.xml | 1 + .../com/android/systemui/SysuiTestCase.java | 7 +- .../android/systemui/qs/QSFragmentTest.java | 11 + .../systemui/statusbar/CommandQueueTest.java | 5 +- .../phone/CollapsedStatusBarFragmentTest.java | 103 +++ .../phone/NavigationBarFragmentTest.java | 12 +- .../systemui/utils/TestableContext.java | 4 + .../utils/leaks/FakeKeyguardMonitor.java | 20 + .../leaks/FakeStatusBarIconController.java | 62 ++ .../systemui/utils/leaks/LeakCheckedTest.java | 4 + 44 files changed, 1560 insertions(+), 817 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/DarkIconDispatcherImpl.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/policy/DarkIconDispatcher.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java create mode 100644 packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java 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 mReceivers = new ArrayMap<>(); + + private int mIconTint = DEFAULT_ICON_TINT; + private float mDarkIntensity; + private int mDarkModeIconColorSingleTone; + private int mLightModeIconColorSingleTone; + + public DarkIconDispatcherImpl(Context context) { + mDarkModeIconColorSingleTone = context.getColor(R.color.dark_mode_icon_color_single_tone); + mLightModeIconColorSingleTone = context.getColor(R.color.light_mode_icon_color_single_tone); + + mTransitionsController = new LightBarTransitionsController(context, + this::setIconTintInternal); + } + + public LightBarTransitionsController getTransitionsController() { + return mTransitionsController; + } + + public void addDarkReceiver(DarkReceiver receiver) { + mReceivers.put(receiver, receiver); + receiver.onDarkChanged(mTintArea, mDarkIntensity, mIconTint); + } + + public void addDarkReceiver(ImageView imageView) { + DarkReceiver receiver = (area, darkIntensity, tint) -> imageView.setImageTintList( + ColorStateList.valueOf(getTint(mTintArea, imageView, mIconTint))); + mReceivers.put(imageView, receiver); + receiver.onDarkChanged(mTintArea, mDarkIntensity, mIconTint); + } + + public void removeDarkReceiver(DarkReceiver object) { + mReceivers.remove(object); + } + + public void removeDarkReceiver(ImageView object) { + mReceivers.remove(object); + } + + public void applyDark(ImageView object) { + mReceivers.get(object).onDarkChanged(mTintArea, mDarkIntensity, mIconTint); + } + + /** + * Sets the dark area so {@link #setIconsDark} only affects the icons in the specified area. + * + * @param darkArea the area in which icons should change it's tint, in logical screen + * coordinates + */ + public void setIconsDarkArea(Rect darkArea) { + if (darkArea == null && mTintArea.isEmpty()) { + return; + } + if (darkArea == null) { + mTintArea.setEmpty(); + } else { + mTintArea.set(darkArea); + } + applyIconTint(); + } + + private void setIconTintInternal(float darkIntensity) { + mDarkIntensity = darkIntensity; + mIconTint = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, + mLightModeIconColorSingleTone, mDarkModeIconColorSingleTone); + applyIconTint(); + } + + private void applyIconTint() { + for (int i = 0; i < mReceivers.size(); i++) { + mReceivers.valueAt(i).onDarkChanged(mTintArea, mDarkIntensity, mIconTint); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java index 7c4588983b4e9..9d699cfba53bc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java @@ -22,6 +22,7 @@ import android.view.View; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.DarkIconDispatcher; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -36,7 +37,7 @@ public class LightBarController implements BatteryController.BatteryStateChangeC private static final float NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD = 0.1f; - private final StatusBarIconController mStatusBarIconController; + private final DarkIconDispatcher mStatusBarIconController; private final BatteryController mBatteryController; private FingerprintUnlockController mFingerprintUnlockController; @@ -65,8 +66,8 @@ public class LightBarController implements BatteryController.BatteryStateChangeC private final Rect mLastFullscreenBounds = new Rect(); private final Rect mLastDockedBounds = new Rect(); - public LightBarController(StatusBarIconController statusBarIconController) { - mStatusBarIconController = statusBarIconController; + public LightBarController() { + mStatusBarIconController = Dependency.get(DarkIconDispatcher.class); mBatteryController = Dependency.get(BatteryController.class); mBatteryController.addCallback(this); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java index 07f37ab01f5c9..6bd959fe2a546 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java @@ -17,13 +17,19 @@ package com.android.systemui.statusbar.phone; import android.animation.ValueAnimator; +import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; import android.util.TimeUtils; import com.android.systemui.Dumpable; +import com.android.systemui.Dependency; import com.android.systemui.Interpolators; +import com.android.systemui.SysUiServiceProvider; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.CommandQueue.Callbacks; +import com.android.systemui.statusbar.policy.KeyguardMonitor; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -31,13 +37,14 @@ import java.io.PrintWriter; /** * Class to control all aspects about light bar changes. */ -public class LightBarTransitionsController implements Dumpable { +public class LightBarTransitionsController implements Dumpable, Callbacks { public static final long DEFAULT_TINT_ANIMATION_DURATION = 120; private static final String EXTRA_DARK_INTENSITY = "dark_intensity"; private final Handler mHandler; private final DarkIntensityApplier mApplier; + private final KeyguardMonitor mKeyguardMonitor; private boolean mTransitionDeferring; private long mTransitionDeferringStartTime; @@ -56,9 +63,17 @@ public class LightBarTransitionsController implements Dumpable { } }; - public LightBarTransitionsController(DarkIntensityApplier applier) { + public LightBarTransitionsController(Context context, DarkIntensityApplier applier) { mApplier = applier; mHandler = new Handler(); + mKeyguardMonitor = Dependency.get(KeyguardMonitor.class); + SysUiServiceProvider.getComponent(context, CommandQueue.class) + .addCallbacks(this); + } + + public void destroy(Context context) { + SysUiServiceProvider.getComponent(context, CommandQueue.class) + .removeCallbacks(this); } public void saveState(Bundle outState) { @@ -71,10 +86,15 @@ public class LightBarTransitionsController implements Dumpable { setIconTintInternal(savedInstanceState.getFloat(EXTRA_DARK_INTENSITY, 0)); } - public void appTransitionPending() { + @Override + public void appTransitionPending(boolean forced) { + if (mKeyguardMonitor.isKeyguardGoingAway() && !forced) { + return; + } mTransitionPending = true; } + @Override public void appTransitionCancelled() { if (mTransitionPending && mTintChangePending) { mTintChangePending = false; @@ -83,7 +103,11 @@ public class LightBarTransitionsController implements Dumpable { mTransitionPending = false; } - public void appTransitionStarting(long startTime, long duration) { + @Override + public void appTransitionStarting(long startTime, long duration, boolean forced) { + if (mKeyguardMonitor.isKeyguardGoingAway() && !forced) { + return; + } if (mTransitionPending && mTintChangePending) { mTintChangePending = false; animateIconTint(mPendingDarkIntensity, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 808cd21088296..99f8aafafdf52 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -118,7 +118,6 @@ public class NavigationBarFragment extends Fragment implements Callbacks { private int mSystemUiVisibility; private LightBarController mLightBarController; - private boolean mKeyguardGoingAway; public boolean mHomeBlockedThisTouch; @@ -195,6 +194,7 @@ public class NavigationBarFragment extends Fragment implements Callbacks { @Override public void onDestroyView() { super.onDestroyView(); + mNavigationBarView.getLightTransitionsController().destroy(getContext()); getContext().unregisterReceiver(mBroadcastReceiver); } @@ -287,31 +287,6 @@ public class NavigationBarFragment extends Fragment implements Callbacks { } } - @Override - public void appTransitionPending() { - mNavigationBarView.getLightTransitionsController().appTransitionPending(); - } - - @Override - public void appTransitionCancelled() { - mNavigationBarView.getLightTransitionsController().appTransitionCancelled(); - } - - @Override - public void appTransitionStarting(long startTime, long duration) { - if (mKeyguardGoingAway) return; - doAppTransitionStarting(startTime, duration); - } - - /** - * Calls appTransitionStarting for the nav bar regardless of whether keyguard is going away. - * public so StatusBar can force this when needed. - */ - public void doAppTransitionStarting(long startTime, long duration) { - mNavigationBarView.getLightTransitionsController().appTransitionStarting(startTime, - duration); - } - // Injected from StatusBar at creation. public void setCurrentSysuiVisibility(int systemUiVisibility) { mSystemUiVisibility = systemUiVisibility; @@ -612,10 +587,6 @@ public class NavigationBarFragment extends Fragment implements Callbacks { delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE); } - public void setKeyguardGoingAway(boolean keyguardGoingAway) { - mKeyguardGoingAway = keyguardGoingAway; - } - public BarTransitions getBarTransitions() { return mNavigationBarView.getBarTransitions(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java index 3be5e57bea64d..cb925d5f7e169 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java @@ -38,7 +38,8 @@ public final class NavigationBarTransitions extends BarTransitions { mView = view; mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); - mLightTransitionsController = new LightBarTransitionsController(this::applyDarkIntensity); + mLightTransitionsController = new LightBarTransitionsController(view.getContext(), + this::applyDarkIntensity); } public void init() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java index 0386398ddae53..6d7ab479d74d7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java @@ -17,6 +17,8 @@ import com.android.systemui.statusbar.NotificationData; import com.android.systemui.statusbar.NotificationShelf; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.notification.NotificationUtils; +import com.android.systemui.statusbar.policy.DarkIconDispatcher; +import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver; import com.android.systemui.statusbar.stack.NotificationStackScrollLayout; import java.util.ArrayList; @@ -26,7 +28,7 @@ import java.util.function.Function; * A controller for the space in the status bar to the left of the system icons. This area is * normally reserved for notifications. */ -public class NotificationIconAreaController { +public class NotificationIconAreaController implements DarkReceiver { private final NotificationColorUtil mNotificationColorUtil; private int mIconSize; @@ -64,11 +66,12 @@ public class NotificationIconAreaController { mNotificationIcons = (NotificationIconContainer) mNotificationIconArea.findViewById( R.id.notificationIcons); - NotificationShelf shelf = mStatusBar.getNotificationShelf(); + mNotificationScrollLayout = mStatusBar.getNotificationScrollLayout(); + } + + public void setupShelf(NotificationShelf shelf) { mShelfIcons = shelf.getShelfIcons(); shelf.setCollapsedIcons(mNotificationIcons); - - mNotificationScrollLayout = mStatusBar.getNotificationScrollLayout(); } public void onDensityOrFontScaleChanged(Context context) { @@ -102,23 +105,18 @@ public class NotificationIconAreaController { } /** - * See {@link StatusBarIconController#setIconsDarkArea}. + * See {@link com.android.systemui.statusbar.policy.DarkIconDispatcher#setIconsDarkArea}. + * Sets the color that should be used to tint any icons in the notification area. * * @param tintArea the area in which to tint the icons, specified in screen coordinates + * @param darkIntensity */ - public void setTintArea(Rect tintArea) { + public void onDarkChanged(Rect tintArea, float darkIntensity, int iconTint) { if (tintArea == null) { mTintArea.setEmpty(); } else { mTintArea.set(tintArea); } - applyNotificationIconsTint(); - } - - /** - * Sets the color that should be used to tint any icons in the notification area. - */ - public void setIconTint(int iconTint) { mIconTint = iconTint; applyNotificationIconsTint(); } @@ -231,7 +229,7 @@ public class NotificationIconAreaController { boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mNotificationColorUtil); if (colorize) { v.setImageTintList(ColorStateList.valueOf( - StatusBarIconController.getTint(mTintArea, v, mIconTint))); + DarkIconDispatcher.getTint(mTintArea, v, mIconTint))); } v.setIconTint(mIconTint); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java index 87a3848190076..23d3816b3ffef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java @@ -166,6 +166,10 @@ public abstract class PanelBar extends FrameLayout { if (DEBUG) LOG("onPanelPeeked"); } + public boolean isClosed() { + return mState == STATE_CLOSED; + } + public void onPanelCollapsed() { if (DEBUG) LOG("onPanelCollapsed"); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 1044ecf7395aa..93f874dc99391 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -38,24 +38,35 @@ import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.SysUiServiceProvider; import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.qs.tiles.RotationLockTile; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.CommandQueue.Callbacks; import com.android.systemui.statusbar.policy.BluetoothController; import com.android.systemui.statusbar.policy.BluetoothController.Callback; import com.android.systemui.statusbar.policy.CastController; import com.android.systemui.statusbar.policy.CastController.CastDevice; import com.android.systemui.statusbar.policy.DataSaverController; +import com.android.systemui.statusbar.policy.DataSaverController.Listener; +import com.android.systemui.statusbar.policy.DeviceProvisionedController; +import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; import com.android.systemui.statusbar.policy.HotspotController; +import com.android.systemui.statusbar.policy.KeyguardMonitor; import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.RotationLockController; +import com.android.systemui.statusbar.policy.RotationLockController.RotationLockControllerCallback; import com.android.systemui.statusbar.policy.UserInfoController; +import com.android.systemui.statusbar.policy.ZenModeController; /** * This class contains all of the policy about which icons are installed in the status * bar at boot time. It goes through the normal API for icons, even though it probably * strictly doesn't need to. */ -public class PhoneStatusBarPolicy implements Callback, RotationLockController.RotationLockControllerCallback, DataSaverController.Listener { +public class PhoneStatusBarPolicy implements Callback, Callbacks, + RotationLockControllerCallback, Listener, + ZenModeController.Callback, DeviceProvisionedListener, KeyguardMonitor.Callback { private static final String TAG = "PhoneStatusBarPolicy"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -82,7 +93,9 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro private final StatusBarIconController mIconController; private final RotationLockController mRotationLockController; private final DataSaverController mDataSaver; - private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; + private final ZenModeController mZenController; + private final DeviceProvisionedController mProvisionedController; + private final KeyguardMonitor mKeyguardMonitor; // Assume it's all good unless we hear otherwise. We don't always seem // to get broadcasts that it *is* there. @@ -106,13 +119,15 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro mCast = Dependency.get(CastController.class); mHotspot = Dependency.get(HotspotController.class); mBluetooth = Dependency.get(BluetoothController.class); - mBluetooth.addCallback(this); mNextAlarm = Dependency.get(NextAlarmController.class); mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); mUserInfoController = Dependency.get(UserInfoController.class); mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mRotationLockController = Dependency.get(RotationLockController.class); mDataSaver = Dependency.get(DataSaverController.class); + mZenController = Dependency.get(ZenModeController.class); + mProvisionedController = Dependency.get(DeviceProvisionedController.class); + mKeyguardMonitor = Dependency.get(KeyguardMonitor.class); mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast); mSlotHotspot = context.getString(com.android.internal.R.string.status_bar_hotspot); @@ -127,7 +142,6 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro mSlotHeadset = context.getString(com.android.internal.R.string.status_bar_headset); mSlotDataSaver = context.getString(com.android.internal.R.string.status_bar_data_saver); - mRotationLockController.addCallback(this); // listen for broadcasts IntentFilter filter = new IntentFilter(); @@ -158,7 +172,6 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro // Alarm clock mIconController.setIcon(mSlotAlarmClock, R.drawable.stat_sys_alarm, null); mIconController.setIconVisibility(mSlotAlarmClock, false); - mNextAlarm.addCallback(mNextAlarmCallback); // zen mIconController.setIcon(mSlotZen, R.drawable.stat_sys_zen_important, null); @@ -172,13 +185,11 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro // cast mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast, null); mIconController.setIconVisibility(mSlotCast, false); - mCast.addCallback(mCastCallback); // hotspot mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_hotspot, mContext.getString(R.string.accessibility_status_bar_hotspot)); mIconController.setIconVisibility(mSlotHotspot, mHotspot.isHotspotEnabled()); - mHotspot.addCallback(mHotspotCallback); // managed profile mIconController.setIcon(mSlotManagedProfile, R.drawable.stat_sys_managed_profile_status, @@ -189,15 +200,36 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro mIconController.setIcon(mSlotDataSaver, R.drawable.stat_sys_data_saver, context.getString(R.string.accessibility_data_saver_on)); mIconController.setIconVisibility(mSlotDataSaver, false); + + mRotationLockController.addCallback(this); + mBluetooth.addCallback(this); + mProvisionedController.addCallback(this); + mZenController.addCallback(this); + mCast.addCallback(mCastCallback); + mHotspot.addCallback(mHotspotCallback); + mNextAlarm.addCallback(mNextAlarmCallback); mDataSaver.addCallback(this); + mKeyguardMonitor.addCallback(this); + + SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallbacks(this); } - public void setStatusBarKeyguardViewManager( - StatusBarKeyguardViewManager statusBarKeyguardViewManager) { - mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; + public void destroy() { + mRotationLockController.removeCallback(this); + mBluetooth.removeCallback(this); + mProvisionedController.removeCallback(this); + mZenController.removeCallback(this); + mCast.removeCallback(mCastCallback); + mHotspot.removeCallback(mHotspotCallback); + mNextAlarm.removeCallback(mNextAlarmCallback); + mDataSaver.removeCallback(this); + mKeyguardMonitor.removeCallback(this); + SysUiServiceProvider.getComponent(mContext, CommandQueue.class).removeCallbacks(this); + mContext.unregisterReceiver(mIntentReceiver); } - public void setZenMode(int zen) { + @Override + public void onZenChanged(int zen) { mZen = zen; updateVolumeZen(); } @@ -394,7 +426,7 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro if (DEBUG) Log.v(TAG, "updateManagedProfile: mManagedProfileFocused: " + mManagedProfileFocused); final boolean showIcon; - if (mManagedProfileFocused && !mStatusBarKeyguardViewManager.isShowing()) { + if (mManagedProfileFocused && !mKeyguardMonitor.isShowing()) { showIcon = true; mIconController.setIcon(mSlotManagedProfile, R.drawable.stat_sys_managed_profile_status, @@ -471,15 +503,20 @@ public class PhoneStatusBarPolicy implements Callback, RotationLockController.Ro } }; - public void appTransitionStarting(long startTime, long duration) { + @Override + public void appTransitionStarting(long startTime, long duration, boolean forced) { updateManagedProfile(); } - public void notifyKeyguardShowingChanged() { + @Override + public void onKeyguardShowingChanged() { updateManagedProfile(); } - public void setCurrentUserSetup(boolean userSetup) { + @Override + public void onUserSetupChanged() { + boolean userSetup = mProvisionedController.isUserSetup( + mProvisionedController.getCurrentUser()); if (mCurrentUserSetup == userSetup) return; mCurrentUserSetup = userSetup; updateAlarm(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index 7e08812435d94..b52c26f143f70 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -24,9 +24,13 @@ import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; +import com.android.systemui.BatteryMeterView; import com.android.systemui.DejankUtils; +import com.android.systemui.Dependency; import com.android.systemui.EventLogTags; import com.android.systemui.R; +import com.android.systemui.statusbar.policy.DarkIconDispatcher; +import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver; public class PhoneStatusBarView extends PanelBar { private static final String TAG = "PhoneStatusBarView"; @@ -48,6 +52,7 @@ public class PhoneStatusBarView extends PanelBar { } } }; + private DarkReceiver mBattery; public PhoneStatusBarView(Context context, AttributeSet attrs) { super(context, attrs); @@ -70,6 +75,20 @@ public class PhoneStatusBarView extends PanelBar { @Override public void onFinishInflate() { mBarTransitions.init(); + mBattery = (DarkReceiver) findViewById(R.id.battery); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + // Always have Battery meters in the status bar observe the dark/light modes. + Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mBattery); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(mBattery); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java index 4307a2e1ac6b5..457ed6cc42379 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java @@ -178,7 +178,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements SignalClusterView cluster = (SignalClusterView) findViewById(R.id.signal_cluster); int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground); float intensity = colorForeground == Color.WHITE ? 0 : 1; - cluster.setIconTint(colorForeground, intensity, new Rect(0, 0, 0, 0)); + cluster.onDarkChanged(new Rect(0, 0, 0, 0), intensity, colorForeground); BatteryMeterView battery = (BatteryMeterView) findViewById(R.id.battery); int colorSecondary = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary); battery.setRawColors(colorForeground, colorSecondary); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 942cf0efe0dbf..433dc3f92e5a1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -173,13 +173,16 @@ import com.android.systemui.statusbar.ScrimView; import com.android.systemui.statusbar.SignalClusterView; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager; import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; import com.android.systemui.statusbar.policy.BrightnessMirrorController; +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.DeviceProvisionedController; import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener; -import com.android.systemui.statusbar.policy.EncryptionHelper; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardMonitor; import com.android.systemui.statusbar.policy.KeyguardMonitorImpl; @@ -504,9 +507,6 @@ public class StatusBar extends SystemUI implements DemoMode, } updateQsExpansionEnabled(); } - if (mIconPolicy != null) { - mIconPolicy.setCurrentUserSetup(mUserSetup); - } } }; @@ -712,6 +712,8 @@ public class StatusBar extends SystemUI implements DemoMode, private BatteryController mBatteryController; private LogMaker mStatusBarStateLog; private LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger(); + private NotificationIconAreaController mNotificationIconAreaController; + private ConfigurationListener mDensityChangeListener; private void recycleAllVisibilityObjects(ArraySet array) { final int N = array.size(); @@ -809,8 +811,6 @@ public class StatusBar extends SystemUI implements DemoMode, final Configuration currentConfig = mContext.getResources().getConfiguration(); mLocale = currentConfig.locale; mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale); - mFontScale = currentConfig.fontScale; - mDensity = currentConfig.densityDpi; mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); @@ -847,7 +847,7 @@ public class StatusBar extends SystemUI implements DemoMode, int N = iconSlots.size(); int viewIndex = 0; for (int i=0; i < N; i++) { - setIcon(iconSlots.get(i), icons.get(i)); + mCommandQueue.setIcon(iconSlots.get(i), icons.get(i)); } // Set up the initial notification state. @@ -914,7 +914,6 @@ public class StatusBar extends SystemUI implements DemoMode, // Lastly, call to the icon policy to install/update all the icons. mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController); - mIconPolicy.setCurrentUserSetup(mUserSetup); mSettingsObserver.onChange(false); // set up mHeadsUpObserver.onChange(true); // set up @@ -938,18 +937,25 @@ public class StatusBar extends SystemUI implements DemoMode, mScreenPinningRequest = new ScreenPinningRequest(mContext); mFalsingManager = FalsingManager.getInstance(mContext); + Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this); + + mDensityChangeListener = new ConfigurationListener() { + @Override + public void onDensityOrFontScaleChanged() { + StatusBar.this.onDensityOrFontScaleChanged(); + } + }; + Dependency.get(ConfigurationController.class).addCallback(mDensityChangeListener); } protected void createIconController() { - mIconController = new StatusBarIconController( - mContext, mStatusBarView, mKeyguardStatusBar, this); } // ================================================================================ // Constructing the view // ================================================================================ - protected PhoneStatusBarView makeStatusBarView() { + protected void makeStatusBarView() { final Context context = mContext; updateDisplaySize(); // populates mDisplayMetrics updateResources(); @@ -958,14 +964,37 @@ public class StatusBar extends SystemUI implements DemoMode, mStatusBarWindow.setService(this); mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener()); + // TODO: Deal with the ugliness that comes from having some of the statusbar broken out + // into fragments, but the rest here, it leaves some awkward lifecycle and whatnot. mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById( R.id.notification_panel); + mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById( + R.id.notification_stack_scroller); mNotificationPanel.setStatusBar(this); mNotificationPanel.setGroupManager(mGroupManager); + mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header); - mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar); - mStatusBarView.setBar(this); - mStatusBarView.setPanel(mNotificationPanel); + mNotificationIconAreaController = SystemUIFactory.getInstance() + .createNotificationIconAreaController(context, this); + inflateShelf(); + mNotificationIconAreaController.setupShelf(mNotificationShelf); + Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController); + FragmentHostManager.get(mStatusBarWindow) + .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> { + CollapsedStatusBarFragment statusBarFragment = (CollapsedStatusBarFragment) fragment; + statusBarFragment.initNotificationIconArea(mNotificationIconAreaController); + mStatusBarView = (PhoneStatusBarView) fragment.getView(); + mStatusBarView.setBar(this); + mStatusBarView.setPanel(mNotificationPanel); + mStatusBarView.setScrimController(mScrimController); + setAreThereNotifications(); + }).getFragmentManager() + .beginTransaction() + .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(), CollapsedStatusBarFragment.TAG) + .commit(); + Dependency.get(StatusBarIconController.class).addIconGroup( + new IconManager((ViewGroup) mKeyguardStatusBar.findViewById(R.id.statusIcons))); + mIconController = Dependency.get(StatusBarIconController.class); if (!ActivityManager.isHighEndGfx()) { mStatusBarWindow.setBackground(null); @@ -1003,8 +1032,6 @@ public class StatusBar extends SystemUI implements DemoMode, // figure out which pixel-format to use for the status bar. mPixelFormat = PixelFormat.OPAQUE; - mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById( - R.id.notification_stack_scroller); mStackScroller.setLongPressListener(getNotificationLongClicker()); mStackScroller.setStatusBar(this); mStackScroller.setGroupManager(mGroupManager); @@ -1012,7 +1039,6 @@ public class StatusBar extends SystemUI implements DemoMode, mGroupManager.setOnGroupChangeListener(mStackScroller); mVisualStabilityManager.setVisibilityLocationProvider(mStackScroller); - inflateShelf(); inflateEmptyShadeView(); inflateDismissView(); mExpandedContents = mStackScroller; @@ -1025,7 +1051,6 @@ public class StatusBar extends SystemUI implements DemoMode, mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler); } - mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header); mKeyguardStatusView = (KeyguardStatusView) mStatusBarWindow.findViewById(R.id.keyguard_status_view); mKeyguardBottomArea = @@ -1039,8 +1064,6 @@ public class StatusBar extends SystemUI implements DemoMode, // set the initial view visibility setAreThereNotifications(); - createIconController(); - // TODO: Find better place for this callback. mBatteryController.addCallback(new BatteryStateChangeCallback() { @Override @@ -1057,7 +1080,7 @@ public class StatusBar extends SystemUI implements DemoMode, } }); - mLightBarController = new LightBarController(mIconController); + mLightBarController = new LightBarController(); if (mNavigationBar != null) { mNavigationBar.setLightBarController(mLightBarController); } @@ -1081,7 +1104,6 @@ public class StatusBar extends SystemUI implements DemoMode, } mHeadsUpManager.addListener(mScrimController); mStackScroller.setScrimController(mScrimController); - mStatusBarView.setScrimController(mScrimController); mDozeScrimController = new DozeScrimController(mScrimController, context, mStackScroller, mNotificationPanel); @@ -1187,8 +1209,6 @@ public class StatusBar extends SystemUI implements DemoMode, // Private API call to make the shadows look better for Recents ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f)); - - return mStatusBarView; } protected void createNavigationBar() { @@ -1262,12 +1282,13 @@ public class StatusBar extends SystemUI implements DemoMode, } // end old BaseStatusBar.onDensityOrFontScaleChanged(). mScrimController.onDensityOrFontScaleChanged(); - mStatusBarView.onDensityOrFontScaleChanged(); + // TODO: Remove this. + if (mStatusBarView != null) mStatusBarView.onDensityOrFontScaleChanged(); if (mBrightnessMirrorController != null) { mBrightnessMirrorController.onDensityOrFontScaleChanged(); } inflateSignalClusters(); - mIconController.onDensityOrFontScaleChanged(); + mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext); inflateDismissView(); updateClearAll(); inflateEmptyShadeView(); @@ -1283,12 +1304,11 @@ public class StatusBar extends SystemUI implements DemoMode, } private void inflateSignalClusters() { - SignalClusterView signalClusterView = reinflateSignalCluster(mStatusBarView); - mIconController.setSignalCluster(signalClusterView); reinflateSignalCluster(mKeyguardStatusBar); } - private SignalClusterView reinflateSignalCluster(View view) { + public static SignalClusterView reinflateSignalCluster(View view) { + Context context = view.getContext(); SignalClusterView signalCluster = (SignalClusterView) view.findViewById(R.id.signal_cluster); if (signalCluster != null) { @@ -1297,12 +1317,12 @@ public class StatusBar extends SystemUI implements DemoMode, ViewGroup viewParent = (ViewGroup) parent; int index = viewParent.indexOfChild(signalCluster); viewParent.removeView(signalCluster); - SignalClusterView newCluster = (SignalClusterView) LayoutInflater.from(mContext) + SignalClusterView newCluster = (SignalClusterView) LayoutInflater.from(context) .inflate(R.layout.signal_cluster_view, viewParent, false); ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) viewParent.getLayoutParams(); layoutParams.setMarginsRelative( - mContext.getResources().getDimensionPixelSize( + context.getResources().getDimensionPixelSize( R.dimen.signal_cluster_margin_start), 0, 0, 0); newCluster.setLayoutParams(layoutParams); @@ -1426,9 +1446,6 @@ public class StatusBar extends SystemUI implements DemoMode, updateNotifications(); } // end old BaseStatusBar.setZenMode(). - if (mIconPolicy != null) { - mIconPolicy.setZenMode(mode); - } } protected void startKeyguard() { @@ -1445,7 +1462,6 @@ public class StatusBar extends SystemUI implements DemoMode, mKeyguardIndicationController.setUserInfoController( Dependency.get(UserInfoController.class)); mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); - mIconPolicy.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); mRemoteInputController.addCallback(mStatusBarKeyguardViewManager); mRemoteInputController.addCallback(new RemoteInputController.Callback() { @@ -1526,16 +1542,6 @@ public class StatusBar extends SystemUI implements DemoMode, } } - @Override - public void setIcon(String slot, StatusBarIcon icon) { - mIconController.setIcon(slot, icon); - } - - @Override - public void removeIcon(String slot) { - mIconController.removeIcon(slot); - } - public UserHandle getCurrentUserHandle() { return new UserHandle(mCurrentUserId); } @@ -1898,7 +1904,7 @@ public class StatusBar extends SystemUI implements DemoMode, updateQsExpansionEnabled(); // Let's also update the icons - mIconController.updateNotificationIcons(mNotificationData); + mNotificationIconAreaController.updateNotificationIcons(mNotificationData); } /** @@ -2079,24 +2085,26 @@ public class StatusBar extends SystemUI implements DemoMode, hasActiveNotifications() + " clearable=" + clearable); } - final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out); - final boolean showDot = hasActiveNotifications() && !areLightsOn(); - if (showDot != (nlo.getAlpha() == 1.0f)) { - if (showDot) { - nlo.setAlpha(0f); - nlo.setVisibility(View.VISIBLE); + if (mStatusBarView != null) { + final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out); + final boolean showDot = hasActiveNotifications() && !areLightsOn(); + if (showDot != (nlo.getAlpha() == 1.0f)) { + if (showDot) { + nlo.setAlpha(0f); + nlo.setVisibility(View.VISIBLE); + } + nlo.animate() + .alpha(showDot ? 1 : 0) + .setDuration(showDot ? 750 : 250) + .setInterpolator(new AccelerateInterpolator(2.0f)) + .setListener(showDot ? null : new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator _a) { + nlo.setVisibility(View.GONE); + } + }) + .start(); } - nlo.animate() - .alpha(showDot?1:0) - .setDuration(showDot?750:250) - .setInterpolator(new AccelerateInterpolator(2.0f)) - .setListener(showDot ? null : new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator _a) { - nlo.setVisibility(View.GONE); - } - }) - .start(); } findAndUpdateMediaNotifications(); @@ -2420,26 +2428,6 @@ public class StatusBar extends SystemUI implements DemoMode, && mFalsingManager.isReportingEnabled() ? View.VISIBLE : View.INVISIBLE); } - protected int adjustDisableFlags(int state) { - if (!mLaunchTransitionFadingAway && !mKeyguardFadingAway && 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 mExpandedVisible && mNotificationPanel.shouldHideNotificationIcons(); - } - /** * State is one or more of the DISABLE constants from StatusBarManager. */ @@ -2448,7 +2436,6 @@ public class StatusBar extends SystemUI implements DemoMode, animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN; mDisabledUnmodified1 = state1; mDisabledUnmodified2 = state2; - state1 = adjustDisableFlags(state1); final int old1 = mDisabled1; final int diff1 = state1 ^ old1; mDisabled1 = state1; @@ -2490,28 +2477,13 @@ public class StatusBar extends SystemUI implements DemoMode, flagdbg.append(">"); Log.d(TAG, flagdbg.toString()); - if ((diff1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { - if ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) { - mIconController.hideSystemIconArea(animate); - } else { - mIconController.showSystemIconArea(animate); - } - } - - if ((diff1 & StatusBarManager.DISABLE_CLOCK) != 0) { - boolean visible = (state1 & StatusBarManager.DISABLE_CLOCK) == 0; - mIconController.setClockVisibilityByPolicy(visible); - } if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) { if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) { animateCollapsePanels(); } } - if ((diff1 & (StatusBarManager.DISABLE_HOME - | StatusBarManager.DISABLE_RECENT - | StatusBarManager.DISABLE_BACK - | StatusBarManager.DISABLE_SEARCH)) != 0) { + if ((diff1 & StatusBarManager.DISABLE_RECENT) != 0) { if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) { // close recents if it's visible mHandler.removeMessages(MSG_HIDE_RECENT_APPS); @@ -2519,14 +2491,6 @@ public class StatusBar extends SystemUI implements DemoMode, } } - if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { - if ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) { - mIconController.hideNotificationIconArea(animate); - } else { - mIconController.showNotificationIconArea(animate); - } - } - if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) { mDisableNotificationAlerts = (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0; @@ -2740,10 +2704,6 @@ public class StatusBar extends SystemUI implements DemoMode, mFalsingManager.onScreenOff(); } - public NotificationShelf getNotificationShelf() { - return mNotificationShelf; - } - public NotificationStackScrollLayout getNotificationScrollLayout() { return mStackScroller; } @@ -2757,6 +2717,14 @@ public class StatusBar extends SystemUI implements DemoMode, updateNotifications(); } + public boolean isLaunchTransitionFadingAway() { + return mLaunchTransitionFadingAway; + } + + public boolean shouldHideNotificationIcons() { + return mNotificationPanel.shouldHideNotificationIcons(); + } + /** * All changes to the status bar and notifications funnel through here and are batched. */ @@ -3162,7 +3130,8 @@ public class StatusBar extends SystemUI implements DemoMode, void checkBarModes() { if (mDemoMode) return; - checkBarMode(mStatusBarMode, mStatusBarWindowState, getStatusBarTransitions()); + if (mStatusBarView != null) checkBarMode(mStatusBarMode, mStatusBarWindowState, + getStatusBarTransitions()); if (mNavigationBar != null) mNavigationBar.checkNavBarModes(); mNoAnimationOnNextBarModeChange = false; } @@ -3183,7 +3152,9 @@ public class StatusBar extends SystemUI implements DemoMode, } private void finishBarAnimations() { - mStatusBarView.getBarTransitions().finishAnimations(); + if (mStatusBarView != null) { + mStatusBarView.getBarTransitions().finishAnimations(); + } if (mNavigationBar != null) { mNavigationBar.finishBarAnimations(); } @@ -3363,8 +3334,6 @@ public class StatusBar extends SystemUI implements DemoMode, mNotificationData.dump(pw, " "); } - mIconController.dump(pw); - if (false) { pw.println("see the logcat for a dump of the views we have created."); // must happen on ui thread @@ -3617,15 +3586,6 @@ public class StatusBar extends SystemUI implements DemoMode, protected void onConfigurationChanged(Configuration newConfig) { updateResources(); updateDisplaySize(); // populates mDisplayMetrics - // Begin old BaseStatusBar.onConfigurationChanged - final float fontScale = newConfig.fontScale; - final int density = newConfig.densityDpi; - if (density != mDensity || mFontScale != fontScale) { - onDensityOrFontScaleChanged(); - mDensity = density; - mFontScale = fontScale; - } - // End old BaseStatusBar.onConfigurationChanged if (DEBUG) { Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration()); @@ -3946,17 +3906,12 @@ public class StatusBar extends SystemUI implements DemoMode, mContext.unregisterReceiver(mDemoReceiver); mAssistManager.destroy(); - final SignalClusterView signalCluster = - (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster); - final SignalClusterView signalClusterKeyguard = - (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster); - final SignalClusterView signalClusterQs = - (SignalClusterView) mHeader.findViewById(R.id.signal_cluster); if (mQSPanel != null && mQSPanel.getHost() != null) { mQSPanel.getHost().destroy(); } Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(null); mDeviceProvisionedController.removeCallback(mUserSetupObserver); + Dependency.get(ConfigurationController.class).removeCallback(mDensityChangeListener); } private boolean mDemoModeAllowed; @@ -3989,7 +3944,7 @@ public class StatusBar extends SystemUI implements DemoMode, mBatteryController.dispatchDemoCommand(command, args); } if (modeChange || command.equals(COMMAND_STATUS)) { - mIconController.dispatchDemoCommand(command, args); + ((StatusBarIconControllerImpl) mIconController).dispatchDemoCommand(command, args); } if (mNetworkController != null && (modeChange || command.equals(COMMAND_NETWORK))) { mNetworkController.dispatchDemoCommand(command, args); @@ -4132,14 +4087,8 @@ public class StatusBar extends SystemUI implements DemoMode, onLaunchTransitionFadingEnded(); } }); - mIconController.getTransitionsController().appTransitionStarting( - SystemClock.uptimeMillis(), - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION); - if (mNavigationBar != null) { - mNavigationBar.doAppTransitionStarting( - SystemClock.uptimeMillis(), - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION); - } + mCommandQueue.appTransitionStarting(SystemClock.uptimeMillis(), + LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true); } }; if (mNotificationPanel.isLaunchTransitionRunning()) { @@ -4264,11 +4213,8 @@ public class StatusBar extends SystemUI implements DemoMode, // Treat Keyguard exit animation as an app transition to achieve nice transition for status // bar. mKeyguardGoingAway = true; - mIconController.getTransitionsController().appTransitionPending(); - if (mNavigationBar != null) { - mNavigationBar.setKeyguardGoingAway(true); - mNavigationBar.appTransitionPending(); - } + mKeyguardMonitor.notifyKeyguardGoingAway(true); + mCommandQueue.appTransitionPending(true); } /** @@ -4283,16 +4229,14 @@ public class StatusBar extends SystemUI implements DemoMode, mKeyguardFadingAwayDelay = delay; mKeyguardFadingAwayDuration = fadeoutDuration; mWaitingForKeyguardExit = false; - mIconController.getTransitionsController().appTransitionStarting( - startTime + fadeoutDuration + mCommandQueue.appTransitionStarting(startTime + fadeoutDuration - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION); + LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true); recomputeDisableFlags(fadeoutDuration > 0 /* animate */); - if (mNavigationBar != null) { - mNavigationBar.doAppTransitionStarting( + mCommandQueue.appTransitionStarting( startTime - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION); - } + LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION, true); + mKeyguardMonitor.notifyKeyguardFadingAway(delay, fadeoutDuration); } public boolean isKeyguardFadingAway() { @@ -4305,9 +4249,7 @@ public class StatusBar extends SystemUI implements DemoMode, public void finishKeyguardFadingAway() { mKeyguardFadingAway = false; mKeyguardGoingAway = false; - if (mNavigationBar != null) { - mNavigationBar.setKeyguardGoingAway(false); - } + mKeyguardMonitor.notifyKeyguardDoneFading(); } public void stopWaitingForKeyguardExit() { @@ -4357,7 +4299,6 @@ public class StatusBar extends SystemUI implements DemoMode, } else { mScrimController.setKeyguardShowing(false); } - mIconPolicy.notifyKeyguardShowingChanged(); mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade); updateDozingState(); updatePublicMode(); @@ -4944,33 +4885,11 @@ public class StatusBar extends SystemUI implements DemoMode, } } - @Override - public void appTransitionPending() { - // Use own timings when Keyguard is going away, see keyguardGoingAway and - // setKeyguardFadingAway - if (!mKeyguardFadingAway) { - mIconController.getTransitionsController().appTransitionPending(); - } - } - @Override public void appTransitionCancelled() { - mIconController.getTransitionsController().appTransitionCancelled(); EventBus.getDefault().send(new AppTransitionFinishedEvent()); } - @Override - public void appTransitionStarting(long startTime, long duration) { - // Use own timings when Keyguard is going away, see keyguardGoingAway and - // setKeyguardFadingAway. - if (!mKeyguardGoingAway) { - mIconController.getTransitionsController().appTransitionStarting(startTime, duration); - } - if (mIconPolicy != null) { - mIconPolicy.appTransitionStarting(startTime, duration); - } - } - @Override public void appTransitionFinished() { EventBus.getDefault().send(new AppTransitionFinishedEvent()); @@ -5180,7 +5099,6 @@ public class StatusBar extends SystemUI implements DemoMode, private boolean mVisibleToUser; private Locale mLocale; - private float mFontScale; protected boolean mUseHeadsUp = false; protected boolean mHeadsUpTicker = false; @@ -5197,7 +5115,6 @@ public class StatusBar extends SystemUI implements DemoMode, private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray(); private UserManager mUserManager; - private int mDensity; protected KeyguardManager mKeyguardManager; private LockPatternUtils mLockPatternUtils; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java index 41f8a91566a9c..c339da761fc92 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -1,502 +1,48 @@ /* - * Copyright (C) 2015 The Android Open Source Project + * 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 + * 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 + * 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.animation.ArgbEvaluator; import android.content.Context; -import android.content.res.ColorStateList; -import android.content.res.Resources; -import android.graphics.Color; -import android.graphics.Rect; -import android.graphics.drawable.Icon; -import android.os.Bundle; -import android.os.UserHandle; import android.text.TextUtils; import android.util.ArraySet; -import android.util.TypedValue; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.TextView; + import com.android.internal.statusbar.StatusBarIcon; -import com.android.systemui.BatteryMeterView; import com.android.systemui.Dependency; -import com.android.systemui.FontSizeUtils; -import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.SystemUIFactory; -import com.android.systemui.statusbar.NotificationData; -import com.android.systemui.statusbar.NotificationShelf; -import com.android.systemui.statusbar.SignalClusterView; import com.android.systemui.statusbar.StatusBarIconView; -import com.android.systemui.tuner.TunerService; -import com.android.systemui.tuner.TunerService.Tunable; +import com.android.systemui.statusbar.policy.DarkIconDispatcher; -import java.io.PrintWriter; -import java.util.ArrayList; +public interface StatusBarIconController { -/** - * Controls everything regarding the icons in the status bar and on Keyguard, including, but not - * limited to: notification icons, signal cluster, additional status icons, and clock in the status - * bar. - */ -public class StatusBarIconController extends StatusBarIconList implements Tunable { + public void addIconGroup(IconManager iconManager); + public void removeIconGroup(IconManager iconManager); + public void setExternalIcon(String slot); + public void setIcon(String slot, int resourceId, CharSequence contentDescription); + public void setIcon(String slot, StatusBarIcon icon); + public void setIconVisibility(String slotTty, boolean b); + public void removeIcon(String slot); public static final String ICON_BLACKLIST = "icon_blacklist"; - public static final int DEFAULT_ICON_TINT = Color.WHITE; - - private Context mContext; - private StatusBar mStatusBar; - private DemoStatusIcons mDemoStatusIcons; - - private LinearLayout mSystemIconArea; - private LinearLayout mStatusIcons; - private SignalClusterView mSignalCluster; - private LinearLayout mStatusIconsKeyguard; - - private NotificationIconAreaController mNotificationIconAreaController; - private View mNotificationIconAreaInner; - private NotificationShelf mNotificationShelf; - - private BatteryMeterView mBatteryMeterView; - private BatteryMeterView mBatteryMeterViewKeyguard; - private TextView mClock; - - private int mIconSize; - private int mIconHPadding; - - private int mIconTint = DEFAULT_ICON_TINT; - private float mDarkIntensity; - private final Rect mTintArea = new Rect(); - private static final Rect sTmpRect = new Rect(); - private static final int[] sTmpInt2 = new int[2]; - - private int mDarkModeIconColorSingleTone; - private int mLightModeIconColorSingleTone; - - private final LightBarTransitionsController mTransitionsController; - - private boolean mClockVisibleByPolicy = true; - private boolean mClockVisibleByUser = true; - - private final ArraySet mIconBlacklist = new ArraySet<>(); - - public StatusBarIconController(Context context, View statusBar, View keyguardStatusBar, - StatusBar phoneStatusBar) { - super(context.getResources().getStringArray( - com.android.internal.R.array.config_statusBarIcons)); - mContext = context; - mStatusBar = phoneStatusBar; - mSystemIconArea = (LinearLayout) statusBar.findViewById(R.id.system_icon_area); - mStatusIcons = (LinearLayout) statusBar.findViewById(R.id.statusIcons); - mSignalCluster = (SignalClusterView) statusBar.findViewById(R.id.signal_cluster); - - mNotificationShelf = phoneStatusBar.getNotificationShelf(); - mNotificationIconAreaController = SystemUIFactory.getInstance() - .createNotificationIconAreaController(context, phoneStatusBar); - mNotificationIconAreaInner = - mNotificationIconAreaController.getNotificationInnerAreaView(); - - ViewGroup notificationIconArea = - (ViewGroup) statusBar.findViewById(R.id.notification_icon_area); - notificationIconArea.addView(mNotificationIconAreaInner); - - mStatusIconsKeyguard = (LinearLayout) keyguardStatusBar.findViewById(R.id.statusIcons); - - mBatteryMeterView = (BatteryMeterView) statusBar.findViewById(R.id.battery); - mBatteryMeterViewKeyguard = (BatteryMeterView) keyguardStatusBar.findViewById(R.id.battery); - scaleBatteryMeterViews(context); - - mClock = (TextView) statusBar.findViewById(R.id.clock); - mDarkModeIconColorSingleTone = context.getColor(R.color.dark_mode_icon_color_single_tone); - mLightModeIconColorSingleTone = context.getColor(R.color.light_mode_icon_color_single_tone); - loadDimens(); - - Dependency.get(TunerService.class).addTunable(this, ICON_BLACKLIST); - - mTransitionsController = new LightBarTransitionsController(this::setIconTintInternal); - } - - public void setSignalCluster(SignalClusterView signalCluster) { - mSignalCluster = signalCluster; - } - - public LightBarTransitionsController getTransitionsController() { - return mTransitionsController; - } - - /** - * Looks up the scale factor for status bar icons and scales the battery view by that amount. - */ - private void scaleBatteryMeterViews(Context context) { - Resources res = context.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); - - mBatteryMeterView.setLayoutParams(scaledLayoutParams); - mBatteryMeterViewKeyguard.setLayoutParams(scaledLayoutParams); - } - - @Override - public void onTuningChanged(String key, String newValue) { - if (!ICON_BLACKLIST.equals(key)) { - return; - } - mIconBlacklist.clear(); - mIconBlacklist.addAll(getIconBlacklist(newValue)); - ArrayList views = new ArrayList(); - // Get all the current views. - for (int i = 0; i < mStatusIcons.getChildCount(); i++) { - views.add((StatusBarIconView) mStatusIcons.getChildAt(i)); - } - // Remove all the icons. - for (int i = views.size() - 1; i >= 0; i--) { - removeIcon(views.get(i).getSlot()); - } - // Add them all back - for (int i = 0; i < views.size(); i++) { - setIcon(views.get(i).getSlot(), views.get(i).getStatusBarIcon()); - } - - setClockVisibleByUser(!StatusBarIconController.getIconBlacklist(newValue) - .contains("clock")); - updateClockVisibility(); - } - private void loadDimens() { - mIconSize = mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_icon_size); - mIconHPadding = mContext.getResources().getDimensionPixelSize( - R.dimen.status_bar_icon_padding); - } - - private void addSystemIcon(int index, StatusBarIcon icon) { - String slot = getSlot(index); - int viewIndex = getViewIndex(index); - boolean blocked = mIconBlacklist.contains(slot); - StatusBarIconView view = new StatusBarIconView(mContext, slot, null, blocked); - view.set(icon); - - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize); - lp.setMargins(mIconHPadding, 0, mIconHPadding, 0); - mStatusIcons.addView(view, viewIndex, lp); - - view = new StatusBarIconView(mContext, slot, null, blocked); - view.set(icon); - mStatusIconsKeyguard.addView(view, viewIndex, new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, mIconSize)); - applyIconTint(); - } - - public void setIcon(String slot, int resourceId, CharSequence contentDescription) { - int index = getSlotIndex(slot); - StatusBarIcon icon = getIcon(index); - if (icon == null) { - icon = new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(), - Icon.createWithResource(mContext, resourceId), 0, 0, contentDescription); - setIcon(slot, icon); - } else { - icon.icon = Icon.createWithResource(mContext, resourceId); - icon.contentDescription = contentDescription; - handleSet(index, icon); - } - } - - public void setExternalIcon(String slot) { - int viewIndex = getViewIndex(getSlotIndex(slot)); - int height = mContext.getResources().getDimensionPixelSize( - R.dimen.status_bar_icon_drawing_size); - ImageView imageView = (ImageView) mStatusIcons.getChildAt(viewIndex); - imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); - imageView.setAdjustViewBounds(true); - setHeightAndCenter(imageView, height); - imageView = (ImageView) mStatusIconsKeyguard.getChildAt(viewIndex); - imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); - imageView.setAdjustViewBounds(true); - setHeightAndCenter(imageView, height); - } - - private void setHeightAndCenter(ImageView imageView, int height) { - ViewGroup.LayoutParams params = imageView.getLayoutParams(); - params.height = height; - if (params instanceof LinearLayout.LayoutParams) { - ((LinearLayout.LayoutParams) params).gravity = Gravity.CENTER_VERTICAL; - } - imageView.setLayoutParams(params); - } - - public void setIcon(String slot, StatusBarIcon icon) { - setIcon(getSlotIndex(slot), icon); - } - - public void removeIcon(String slot) { - int index = getSlotIndex(slot); - removeIcon(index); - } - - public void setIconVisibility(String slot, boolean visibility) { - int index = getSlotIndex(slot); - StatusBarIcon icon = getIcon(index); - if (icon == null || icon.visible == visibility) { - return; - } - icon.visible = visibility; - handleSet(index, icon); - } - - @Override - public void removeIcon(int index) { - if (getIcon(index) == null) { - return; - } - super.removeIcon(index); - int viewIndex = getViewIndex(index); - mStatusIcons.removeViewAt(viewIndex); - mStatusIconsKeyguard.removeViewAt(viewIndex); - } - - @Override - public void setIcon(int index, StatusBarIcon icon) { - if (icon == null) { - removeIcon(index); - return; - } - boolean isNew = getIcon(index) == null; - super.setIcon(index, icon); - if (isNew) { - addSystemIcon(index, icon); - } else { - handleSet(index, icon); - } - } - - private void handleSet(int index, StatusBarIcon icon) { - int viewIndex = getViewIndex(index); - StatusBarIconView view = (StatusBarIconView) mStatusIcons.getChildAt(viewIndex); - view.set(icon); - view = (StatusBarIconView) mStatusIconsKeyguard.getChildAt(viewIndex); - view.set(icon); - applyIconTint(); - } - - public void updateNotificationIcons(NotificationData notificationData) { - mNotificationIconAreaController.updateNotificationIcons(notificationData); - } - - 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); - } - - public void setClockVisibleByUser(boolean visible) { - mClockVisibleByUser = visible; - updateClockVisibility(); - } - - public void setClockVisibilityByPolicy(boolean visible) { - mClockVisibleByPolicy = visible; - updateClockVisibility(); - } - - private void updateClockVisibility() { - int visibility = (mClockVisibleByPolicy && mClockVisibleByUser) - ? View.VISIBLE : View.GONE; - mClock.setVisibility(visibility); - } - - public void dump(PrintWriter pw) { - int N = mStatusIcons.getChildCount(); - pw.println(" icon views: " + N); - for (int i=0; i mIconGroups = new ArrayList<>(); + + private final ArraySet mIconBlacklist = new ArraySet<>(); + + public StatusBarIconControllerImpl(Context context) { + super(context.getResources().getStringArray( + com.android.internal.R.array.config_statusBarIcons)); + Dependency.get(ConfigurationController.class).addCallback(this); + mDarkIconDispatcher = Dependency.get(DarkIconDispatcher.class); + mContext = context; + + loadDimens(); + + SysUiServiceProvider.getComponent(context, CommandQueue.class) + .addCallbacks(this); + Dependency.get(TunerService.class).addTunable(this, ICON_BLACKLIST); + } + + @Override + public void addIconGroup(IconManager group) { + mIconGroups.add(group); + for (int i = 0; i < mIcons.size(); i++) { + StatusBarIcon icon = mIcons.get(i); + if (icon != null) { + String slot = mSlots.get(i); + boolean blocked = mIconBlacklist.contains(slot); + group.onIconAdded(getViewIndex(getSlotIndex(slot)), slot, blocked, icon); + } + } + } + + @Override + public void removeIconGroup(IconManager group) { + group.destroy(); + mIconGroups.remove(group); + } + + @Override + public void onTuningChanged(String key, String newValue) { + if (!ICON_BLACKLIST.equals(key)) { + return; + } + mIconBlacklist.clear(); + mIconBlacklist.addAll(StatusBarIconController.getIconBlacklist(newValue)); + ArrayList current = new ArrayList<>(mIcons); + ArrayList currentSlots = new ArrayList<>(mSlots); + // Remove all the icons. + for (int i = current.size() - 1; i >= 0; i--) { + removeIcon(currentSlots.get(i)); + } + // Add them all back + for (int i = 0; i < current.size(); i++) { + setIcon(currentSlots.get(i), current.get(i)); + } + } + + private void loadDimens() { + } + + private void addSystemIcon(int index, StatusBarIcon icon) { + String slot = getSlot(index); + int viewIndex = getViewIndex(index); + boolean blocked = mIconBlacklist.contains(slot); + + mIconGroups.forEach(l -> l.onIconAdded(viewIndex, slot, blocked, icon)); + } + + @Override + public void setIcon(String slot, int resourceId, CharSequence contentDescription) { + int index = getSlotIndex(slot); + StatusBarIcon icon = getIcon(index); + if (icon == null) { + icon = new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(), + Icon.createWithResource(mContext, resourceId), 0, 0, contentDescription); + setIcon(slot, icon); + } else { + icon.icon = Icon.createWithResource(mContext, resourceId); + icon.contentDescription = contentDescription; + handleSet(index, icon); + } + } + + @Override + public void setExternalIcon(String slot) { + int viewIndex = getViewIndex(getSlotIndex(slot)); + int height = mContext.getResources().getDimensionPixelSize( + R.dimen.status_bar_icon_drawing_size); + mIconGroups.forEach(l -> l.onIconExternal(viewIndex, height)); + } + + @Override + public void setIcon(String slot, StatusBarIcon icon) { + setIcon(getSlotIndex(slot), icon); + } + + @Override + public void removeIcon(String slot) { + int index = getSlotIndex(slot); + removeIcon(index); + } + + public void setIconVisibility(String slot, boolean visibility) { + int index = getSlotIndex(slot); + StatusBarIcon icon = getIcon(index); + if (icon == null || icon.visible == visibility) { + return; + } + icon.visible = visibility; + handleSet(index, icon); + } + + @Override + public void removeIcon(int index) { + if (getIcon(index) == null) { + return; + } + super.removeIcon(index); + int viewIndex = getViewIndex(index); + mIconGroups.forEach(l -> l.onRemoveIcon(viewIndex)); + } + + @Override + public void setIcon(int index, StatusBarIcon icon) { + if (icon == null) { + removeIcon(index); + return; + } + boolean isNew = getIcon(index) == null; + super.setIcon(index, icon); + if (isNew) { + addSystemIcon(index, icon); + } else { + handleSet(index, icon); + } + } + + private void handleSet(int index, StatusBarIcon icon) { + int viewIndex = getViewIndex(index); + mIconGroups.forEach(l -> l.onSetIcon(viewIndex, icon)); + } + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + // TODO: Dump info about all icon groups? + ViewGroup statusIcons = mIconGroups.get(0).mGroup; + int N = statusIcons.getChildCount(); + pw.println(" icon views: " + N); + for (int i = 0; i < N; i++) { + StatusBarIconView ic = (StatusBarIconView) statusIcons.getChildAt(i); + pw.println(" [" + i + "] icon=" + ic); + } + super.dump(pw); + } + + public void dispatchDemoCommand(String command, Bundle args) { + if (mDemoStatusIcons == null) { + // TODO: Rework how we handle demo mode. + int iconSize = mContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.status_bar_icon_size); + mDemoStatusIcons = new DemoStatusIcons((LinearLayout) mIconGroups.get(0).mGroup, + iconSize); + } + mDemoStatusIcons.dispatchDemoCommand(command, args); + } + + @Override + public void onDensityOrFontScaleChanged() { + loadDimens(); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java index 660672d191cb0..f6009082b88a6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java @@ -22,8 +22,8 @@ import java.io.PrintWriter; import java.util.ArrayList; public class StatusBarIconList { - private ArrayList mSlots = new ArrayList<>(); - private ArrayList mIcons = new ArrayList<>(); + protected ArrayList mSlots = new ArrayList<>(); + protected ArrayList mIcons = new ArrayList<>(); public StatusBarIconList(String[] slots) { final int N = slots.length; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java index ffc0d97649663..bb0748cbbdf3e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java @@ -19,11 +19,14 @@ package com.android.systemui.statusbar.policy; import libcore.icu.LocaleData; import android.app.ActivityManager; +import android.app.StatusBarManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Configuration; import android.content.res.TypedArray; +import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; @@ -35,12 +38,18 @@ import android.text.style.CharacterStyle; import android.text.style.RelativeSizeSpan; import android.util.AttributeSet; import android.view.Display; +import android.view.View; import android.widget.TextView; import com.android.systemui.DemoMode; import com.android.systemui.Dependency; +import com.android.systemui.FontSizeUtils; import com.android.systemui.R; +import com.android.systemui.SysUiServiceProvider; +import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.StatusBarIconController; +import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; +import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; @@ -52,10 +61,14 @@ import java.util.TimeZone; /** * Digital clock for the status bar. */ -public class Clock extends TextView implements DemoMode, Tunable { +public class Clock extends TextView implements DemoMode, Tunable, CommandQueue.Callbacks, + DarkReceiver, ConfigurationListener { public static final String CLOCK_SECONDS = "clock_seconds"; + private boolean mClockVisibleByPolicy = true; + private boolean mClockVisibleByUser = true; + private boolean mAttached; private Calendar mCalendar; private String mClockFormatString; @@ -110,6 +123,8 @@ public class Clock extends TextView implements DemoMode, Tunable { null, Dependency.get(Dependency.TIME_TICK_HANDLER)); Dependency.get(TunerService.class).addTunable(this, CLOCK_SECONDS, StatusBarIconController.ICON_BLACKLIST); + SysUiServiceProvider.getComponent(getContext(), CommandQueue.class).addCallbacks(this); + Dependency.get(DarkIconDispatcher.class).addDarkReceiver(this); } // NOTE: It's safe to do these after registering the receiver since the receiver always runs @@ -130,6 +145,9 @@ public class Clock extends TextView implements DemoMode, Tunable { getContext().unregisterReceiver(mIntentReceiver); mAttached = false; Dependency.get(TunerService.class).removeTunable(this); + SysUiServiceProvider.getComponent(getContext(), CommandQueue.class) + .removeCallbacks(this); + Dependency.get(DarkIconDispatcher.class).removeDarkReceiver(this); } } @@ -158,6 +176,22 @@ public class Clock extends TextView implements DemoMode, Tunable { } }; + public void setClockVisibleByUser(boolean visible) { + mClockVisibleByUser = visible; + updateClockVisibility(); + } + + public void setClockVisibilityByPolicy(boolean visible) { + mClockVisibleByPolicy = visible; + updateClockVisibility(); + } + + private void updateClockVisibility() { + int visibility = (mClockVisibleByPolicy && mClockVisibleByUser) + ? View.VISIBLE : View.GONE; + setVisibility(visibility); + } + final void updateClock() { if (mDemoMode) return; mCalendar.setTimeInMillis(System.currentTimeMillis()); @@ -170,9 +204,38 @@ public class Clock extends TextView implements DemoMode, Tunable { if (CLOCK_SECONDS.equals(key)) { mShowSeconds = newValue != null && Integer.parseInt(newValue) != 0; updateShowSeconds(); + } else { + setClockVisibleByUser(!StatusBarIconController.getIconBlacklist(newValue) + .contains("clock")); + updateClockVisibility(); } } + @Override + public void disable(int state1, int state2, boolean animate) { + boolean clockVisibleByPolicy = (state1 & StatusBarManager.DISABLE_CLOCK) == 0; + if (clockVisibleByPolicy != mClockVisibleByPolicy) { + setClockVisibilityByPolicy(clockVisibleByPolicy); + } + } + + @Override + public void onDarkChanged(Rect area, float darkIntensity, int tint) { + setTextColor(DarkIconDispatcher.getTint(area, this, tint)); + } + + @Override + public void onDensityOrFontScaleChanged() { + FontSizeUtils.updateFontSize(this, R.dimen.status_bar_clock_size); + setPaddingRelative( + mContext.getResources().getDimensionPixelSize( + R.dimen.status_bar_clock_starting_padding), + 0, + mContext.getResources().getDimensionPixelSize( + R.dimen.status_bar_clock_end_padding), + 0); + } + private void updateShowSeconds() { if (mShowSeconds) { // Wait until we have a display to start trying to show seconds. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java new file mode 100644 index 0000000000000..788fda80d4dad --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java @@ -0,0 +1,31 @@ +/* + * 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.policy; + +import android.content.res.Configuration; + +import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; + +/** + * Common listener for configuration or subsets of configuration changes (like density or + * font scaling), providing easy static dependence on these events. + */ +public interface ConfigurationController extends CallbackController { + + interface ConfigurationListener { + default void onConfigChanged(Configuration newConfig) {} + default void onDensityOrFontScaleChanged() {} + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DarkIconDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DarkIconDispatcher.java new file mode 100644 index 0000000000000..58944c6ad571e --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DarkIconDispatcher.java @@ -0,0 +1,92 @@ +/* + * 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.policy; + +import android.graphics.Color; +import android.graphics.Rect; +import android.view.View; +import android.widget.ImageView; + +import com.android.systemui.statusbar.phone.LightBarTransitionsController; + +public interface DarkIconDispatcher { + + void setIconsDarkArea(Rect r); + LightBarTransitionsController getTransitionsController(); + + void addDarkReceiver(DarkReceiver receiver); + void addDarkReceiver(ImageView imageView); + + // Must have been previously been added through one of the addDarkReceive methods above. + void removeDarkReceiver(DarkReceiver object); + void removeDarkReceiver(ImageView object); + + // Used to reapply darkness on an object, must have previously been added through + // addDarkReceiver. + void applyDark(ImageView object); + + int DEFAULT_ICON_TINT = Color.WHITE; + Rect sTmpRect = new Rect(); + int[] sTmpInt2 = new int[2]; + + /** + * @return the tint to apply to {@param view} depending on the desired tint {@param color} and + * the screen {@param tintArea} in which to apply that tint + */ + static int getTint(Rect tintArea, View view, int color) { + if (isInArea(tintArea, view)) { + return color; + } else { + return DEFAULT_ICON_TINT; + } + } + + /** + * @return the dark intensity to apply to {@param view} depending on the desired dark + * {@param intensity} and the screen {@param tintArea} in which to apply that intensity + */ + static float getDarkIntensity(Rect tintArea, View view, float intensity) { + if (isInArea(tintArea, view)) { + return intensity; + } else { + return 0f; + } + } + + /** + * @return true if more than half of the {@param view} area are in {@param area}, false + * otherwise + */ + static boolean isInArea(Rect area, View view) { + if (area.isEmpty()) { + return true; + } + sTmpRect.set(area); + view.getLocationOnScreen(sTmpInt2); + int left = sTmpInt2[0]; + + int intersectStart = Math.max(left, area.left); + int intersectEnd = Math.min(left + view.getWidth(), area.right); + int intersectAmount = Math.max(0, intersectEnd - intersectStart); + + boolean coversFullStatusBar = area.top <= 0; + boolean majorityOfWidth = 2 * intersectAmount > view.getWidth(); + return majorityOfWidth && coversFullStatusBar; + } + + interface DarkReceiver { + void onDarkChanged(Rect area, float darkIntensity, int tint); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java index de47267465cdd..728005dde1311 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java @@ -21,8 +21,12 @@ public interface KeyguardMonitor extends CallbackController { boolean isSecure(); boolean canSkipBouncer(); boolean isShowing(); + boolean isKeyguardFadingAway(); + boolean isKeyguardGoingAway(); + long getKeyguardFadingAwayDuration(); + long getKeyguardFadingAwayDelay(); public interface Callback { - void onKeyguardChanged(); + void onKeyguardShowingChanged(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java index 769f93f88e14c..821e6358972c4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitorImpl.java @@ -18,13 +18,10 @@ package com.android.systemui.statusbar.policy; import android.app.ActivityManager; import android.content.Context; -import android.os.RemoteException; -import android.view.WindowManagerGlobal; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.settings.CurrentUserTracker; -import com.android.systemui.statusbar.policy.KeyguardMonitor.Callback; import java.util.ArrayList; @@ -44,6 +41,10 @@ public class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback private boolean mCanSkipBouncer; private boolean mListening; + private boolean mKeyguardFadingAway; + private long mKeyguardFadingAwayDelay; + private long mKeyguardFadingAwayDuration; + private boolean mKeyguardGoingAway; public KeyguardMonitorImpl(Context context) { mContext = context; @@ -115,8 +116,42 @@ public class KeyguardMonitorImpl extends KeyguardUpdateMonitorCallback } private void notifyKeyguardChanged() { - for (Callback callback : mCallbacks) { - callback.onKeyguardChanged(); - } + mCallbacks.forEach(Callback::onKeyguardShowingChanged); + } + + public void notifyKeyguardFadingAway(long delay, long fadeoutDuration) { + mKeyguardFadingAway = true; + mKeyguardFadingAwayDelay = delay; + mKeyguardFadingAwayDuration = fadeoutDuration; + mCallbacks.forEach(Callback::onKeyguardShowingChanged); + } + + public void notifyKeyguardDoneFading() { + mKeyguardFadingAway = false; + mCallbacks.forEach(Callback::onKeyguardShowingChanged); + } + + @Override + public boolean isKeyguardFadingAway() { + return mKeyguardFadingAway; + } + + @Override + public boolean isKeyguardGoingAway() { + return mKeyguardGoingAway; + } + + @Override + public long getKeyguardFadingAwayDelay() { + return mKeyguardFadingAwayDelay; + } + + @Override + public long getKeyguardFadingAwayDuration() { + return mKeyguardFadingAwayDuration; + } + + public void notifyKeyguardGoingAway(boolean keyguardGoingAway) { + mKeyguardGoingAway = keyguardGoingAway; } } \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index 7a32bf1c8d869..6df4a21807dbf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -850,7 +850,7 @@ public class UserSwitcherController { private final KeyguardMonitor.Callback mCallback = new KeyguardMonitor.Callback() { @Override - public void onKeyguardChanged() { + public void onKeyguardShowingChanged() { notifyAdapters(); } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java index f195f7a89f8d9..8777aa6454bc3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java @@ -36,14 +36,14 @@ public interface ZenModeController extends CallbackController { int getCurrentUser(); boolean isVolumeRestricted(); - public static class Callback { - public void onZenChanged(int zen) {} - public void onConditionsChanged(Condition[] conditions) {} - public void onNextAlarmChanged() {} - public void onZenAvailableChanged(boolean available) {} - public void onEffectsSupressorChanged() {} - public void onManualRuleChanged(ZenRule rule) {} - public void onConfigChanged(ZenModeConfig config) {} + public static interface Callback { + default void onZenChanged(int zen) {} + default void onConditionsChanged(Condition[] conditions) {} + default void onNextAlarmChanged() {} + default void onZenAvailableChanged(boolean available) {} + default void onEffectsSupressorChanged() {} + default void onManualRuleChanged(ZenRule rule) {} + default void onConfigChanged(ZenModeConfig config) {} } } \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java index 489c05bcbe957..0edff86a624bb 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java @@ -42,6 +42,9 @@ import static com.android.systemui.BatteryMeterDrawable.SHOW_PERCENT_SETTING; import com.android.systemui.DemoMode; import com.android.systemui.Dependency; import com.android.systemui.R; +import com.android.systemui.SysUiServiceProvider; +import com.android.systemui.SystemUI; +import com.android.systemui.SystemUIApplication; import com.android.systemui.settings.CurrentUserTracker; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.phone.SystemUIDialog; diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml index 6d6243520b5b9..41b75ffa1d2dc 100644 --- a/packages/SystemUI/tests/AndroidManifest.xml +++ b/packages/SystemUI/tests/AndroidManifest.xml @@ -35,6 +35,7 @@ + diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java index 81a50d9fca58c..12a485ecef4ba 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java @@ -18,11 +18,12 @@ package com.android.systemui; import static org.mockito.Mockito.mock; import android.content.Context; -import android.support.test.InstrumentationRegistry; import android.os.Handler; import android.os.Looper; import android.os.MessageQueue; +import android.support.test.InstrumentationRegistry; import android.util.ArrayMap; +import android.util.Log; import com.android.systemui.utils.TestableContext; import com.android.systemui.utils.leaks.Tracker; @@ -30,17 +31,21 @@ import com.android.systemui.utils.leaks.Tracker; import org.junit.After; import org.junit.Before; +import java.lang.Thread.UncaughtExceptionHandler; + /** * Base class that does System UI specific setup. */ public abstract class SysuiTestCase { + private Throwable mException; private Handler mHandler; protected TestableContext mContext; protected TestDependency mDependency; @Before public void SysuiSetup() throws Exception { + mException = null; System.setProperty("dexmaker.share_classloader", "true"); mContext = new TestableContext(InstrumentationRegistry.getTargetContext(), this); SystemUIFactory.createFromConfig(mContext); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java index f22c1af23efa5..9eac0a0d8b041 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java @@ -24,14 +24,18 @@ import com.android.systemui.statusbar.phone.QuickStatusBarHeader; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.policy.UserSwitcherController; import com.android.systemui.tuner.TunerService; +import com.android.systemui.util.LayoutInflaterBuilder; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import android.content.Context; import android.os.Handler; import android.os.Looper; import android.support.test.runner.AndroidJUnit4; +import android.view.View; +import android.widget.FrameLayout; @RunWith(AndroidJUnit4.class) public class QSFragmentTest extends FragmentTestCase { @@ -42,6 +46,13 @@ public class QSFragmentTest extends FragmentTestCase { @Before public void addLeakCheckDependencies() { + mContext.addMockSystemService(Context.LAYOUT_INFLATER_SERVICE, + new LayoutInflaterBuilder(mContext) + .replace("com.android.systemui.statusbar.policy.SplitClockView", + FrameLayout.class) + .replace("TextClock", View.class) + .build()); + injectTestDependency(Dependency.BG_LOOPER, Looper.getMainLooper()); injectMockDependency(UserSwitcherController.class); injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java index 5b22986f69616..930e560d0fda5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java @@ -41,6 +41,7 @@ public class CommandQueueTest extends SysuiTestCase { mCommandQueue = new CommandQueue(); mCallbacks = mock(Callbacks.class); mCommandQueue.addCallbacks(mCallbacks); + verify(mCallbacks).disable(eq(0), eq(0), eq(false)); } @After @@ -181,7 +182,7 @@ public class CommandQueueTest extends SysuiTestCase { public void testAppTransitionPending() { mCommandQueue.appTransitionPending(); waitForIdleSync(); - verify(mCallbacks).appTransitionPending(); + verify(mCallbacks).appTransitionPending(eq(false)); } @Test @@ -195,7 +196,7 @@ public class CommandQueueTest extends SysuiTestCase { public void testAppTransitionStarting() { mCommandQueue.appTransitionStarting(1, 2); waitForIdleSync(); - verify(mCallbacks).appTransitionStarting(eq(1L), eq(2L)); + verify(mCallbacks).appTransitionStarting(eq(1L), eq(2L), eq(false)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java new file mode 100644 index 0000000000000..cb30df4b2f9d8 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java @@ -0,0 +1,103 @@ +/* + * 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 org.junit.Assert.assertEquals; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import android.app.StatusBarManager; +import android.view.View; +import android.view.ViewPropertyAnimator; + +import com.android.systemui.FragmentTestCase; +import com.android.systemui.R; +import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.policy.KeyguardMonitor; +import com.android.systemui.statusbar.policy.NetworkController; +import com.android.systemui.statusbar.policy.SecurityController; +import com.android.systemui.tuner.TunerService; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +public class CollapsedStatusBarFragmentTest extends FragmentTestCase { + + private NotificationIconAreaController mMockNotificiationAreaController; + private View mNotificationAreaInner; + + public CollapsedStatusBarFragmentTest() { + super(CollapsedStatusBarFragment.class); + } + + @Before + public void setup() { + mContext.putComponent(CommandQueue.class, mock(CommandQueue.class)); + mContext.putComponent(StatusBar.class, mock(StatusBar.class)); + mContext.putComponent(TunerService.class, mock(TunerService.class)); + injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES); + mMockNotificiationAreaController = mock(NotificationIconAreaController.class); + mNotificationAreaInner = mock(View.class); + when(mNotificationAreaInner.animate()).thenReturn(mock(ViewPropertyAnimator.class)); + when(mMockNotificiationAreaController.getNotificationInnerAreaView()).thenReturn( + mNotificationAreaInner); + } + + @Test + public void testDisableNone() throws Exception { + postAndWait(() -> mFragments.dispatchResume()); + + CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment; + fragment.initNotificationIconArea(mMockNotificiationAreaController); + fragment.disable(0, 0, false); + + assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.system_icon_area) + .getVisibility()); + } + + @Test + public void testDisableSystemInfo() throws Exception { + postAndWait(() -> mFragments.dispatchResume()); + + CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment; + fragment.initNotificationIconArea(mMockNotificiationAreaController); + fragment.disable(StatusBarManager.DISABLE_SYSTEM_INFO, 0, false); + + assertEquals(View.INVISIBLE, mFragment.getView().findViewById(R.id.system_icon_area) + .getVisibility()); + + fragment.disable(0, 0, false); + + assertEquals(View.VISIBLE, mFragment.getView().findViewById(R.id.system_icon_area) + .getVisibility()); + } + + @Test + public void testDisableNotifications() throws Exception { + postAndWait(() -> mFragments.dispatchResume()); + + CollapsedStatusBarFragment fragment = (CollapsedStatusBarFragment) mFragment; + fragment.initNotificationIconArea(mMockNotificiationAreaController); + fragment.disable(StatusBarManager.DISABLE_NOTIFICATION_ICONS, 0, false); + + Mockito.verify(mNotificationAreaInner).setVisibility(eq(View.INVISIBLE)); + + fragment.disable(0, 0, false); + + Mockito.verify(mNotificationAreaInner).setVisibility(eq(View.VISIBLE)); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java index a9d6df768fa9d..3bce64fe1f202 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java @@ -15,10 +15,14 @@ package com.android.systemui.statusbar.phone; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import android.content.Context; +import android.os.Looper; +import android.view.Display; import android.view.WindowManager; +import com.android.systemui.Dependency; import com.android.systemui.FragmentTestCase; import com.android.systemui.recents.Recents; import com.android.systemui.stackdivider.Divider; @@ -35,17 +39,21 @@ public class NavigationBarFragmentTest extends FragmentTestCase { @Before public void setup() { + injectTestDependency(Dependency.BG_LOOPER, Looper.getMainLooper()); mContext.putComponent(CommandQueue.class, mock(CommandQueue.class)); mContext.putComponent(StatusBar.class, mock(StatusBar.class)); mContext.putComponent(Recents.class, mock(Recents.class)); mContext.putComponent(Divider.class, mock(Divider.class)); - mContext.addMockSystemService(Context.WINDOW_SERVICE, mock(WindowManager.class)); injectLeakCheckedDependencies(ALL_SUPPORTED_CLASSES); + WindowManager windowManager = mock(WindowManager.class); + Display defaultDisplay = mContext.getSystemService(WindowManager.class).getDefaultDisplay(); + when(windowManager.getDefaultDisplay()).thenReturn( + defaultDisplay); + mContext.addMockSystemService(Context.WINDOW_SERVICE, windowManager); } @Test public void testHomeLongPress() { - mContext.addMockSystemService(Context.WINDOW_SERVICE, mock(WindowManager.class)); NavigationBarFragment navigationBarFragment = (NavigationBarFragment) mFragment; postAndWait(() -> mFragments.dispatchResume()); diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java index 62c007f971b94..c4f10035a8c46 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java @@ -30,6 +30,7 @@ import android.os.IBinder; import android.os.UserHandle; import android.provider.Settings; import android.util.ArrayMap; +import android.view.LayoutInflater; import com.android.systemui.SysUiServiceProvider; import com.android.systemui.utils.leaks.Tracker; @@ -99,6 +100,9 @@ public class TestableContext extends ContextWrapper implements SysUiServiceProvi if (mMockSystemServices != null && mMockSystemServices.containsKey(name)) { return mMockSystemServices.get(name); } + if (name.equals(LAYOUT_INFLATER_SERVICE)) { + return getBaseContext().getSystemService(LayoutInflater.class).cloneInContext(this); + } return super.getSystemService(name); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java index 39bbf2dfc42d7..21871fc4cb756 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeKeyguardMonitor.java @@ -44,6 +44,26 @@ public class FakeKeyguardMonitor implements KeyguardMonitor { return false; } + @Override + public boolean isKeyguardFadingAway() { + return false; + } + + @Override + public boolean isKeyguardGoingAway() { + return false; + } + + @Override + public long getKeyguardFadingAwayDuration() { + return 0; + } + + @Override + public long getKeyguardFadingAwayDelay() { + return 0; + } + @Override public boolean canSkipBouncer() { return false; diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java new file mode 100644 index 0000000000000..b13535f75aeea --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeStatusBarIconController.java @@ -0,0 +1,62 @@ +/* + * 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.utils.leaks; + +import com.android.internal.statusbar.StatusBarIcon; +import com.android.systemui.statusbar.phone.StatusBarIconController; +import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager; + +public class FakeStatusBarIconController extends BaseLeakChecker + implements StatusBarIconController { + + public FakeStatusBarIconController(LeakCheckedTest test) { + super(test, "StatusBarGroup"); + } + + @Override + public void addIconGroup(IconManager iconManager) { + addCallback(iconManager); + } + + @Override + public void removeIconGroup(IconManager iconManager) { + removeCallback(iconManager); + } + + @Override + public void setExternalIcon(String slot) { + + } + + @Override + public void setIcon(String slot, int resourceId, CharSequence contentDescription) { + + } + + @Override + public void setIcon(String slot, StatusBarIcon icon) { + + } + + @Override + public void setIconVisibility(String slotTty, boolean b) { + + } + + @Override + public void removeIcon(String slot) { + + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java index c2048c7884dea..6ff80983f3ef2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/LeakCheckedTest.java @@ -22,6 +22,7 @@ import android.util.ArrayMap; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.PluginManager; import com.android.systemui.statusbar.phone.ManagedProfileController; +import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.BluetoothController; import com.android.systemui.statusbar.policy.CallbackController; @@ -75,6 +76,7 @@ public abstract class LeakCheckedTest extends SysuiTestCase { NetworkController.class, PluginManager.class, TunerService.class, + StatusBarIconController.class, }; @Rule @@ -121,6 +123,8 @@ public abstract class LeakCheckedTest extends SysuiTestCase { obj = new FakePluginManager(mContext, this); } else if (cls == TunerService.class) { obj = new FakeTunerService(mContext, this); + } else if (cls == StatusBarIconController.class) { + obj = new FakeStatusBarIconController(this); } else { Assert.fail(cls.getName() + " is not supported by LeakCheckedTest yet"); }