diff options
author | Lucas Dupin <dupin@google.com> | 2017-07-17 15:45:06 -0700 |
---|---|---|
committer | Lucas Dupin <dupin@google.com> | 2017-07-24 13:26:22 -0700 |
commit | e17ce5286f2c25c2ce440b30f476e9e88a6d1e8e (patch) | |
tree | ca33ca59ca8f6307c57d06246458e0bc8b887634 | |
parent | f5c39226458537b7816d36339b4f343eac064b39 (diff) |
Fix jank when switching themes
Turning overlays on and off takes time,
it also doesn't allow us to have fine control
over which view is using which theme.
Lock screen colors are now driven by themes.
Change-Id: Ie8860d00dbb0705ed76edf60a9d3030618dd21ca
Fixes: 63751714
Test: Visual. Set wallpapers, unlock.
Test: runtest -x packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
Test: runtest -x tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java
Test: systrace
22 files changed, 308 insertions, 194 deletions
diff --git a/core/java/com/android/internal/colorextraction/ColorExtractor.java b/core/java/com/android/internal/colorextraction/ColorExtractor.java index 68cf5cd74431..477285e63f37 100644 --- a/core/java/com/android/internal/colorextraction/ColorExtractor.java +++ b/core/java/com/android/internal/colorextraction/ColorExtractor.java @@ -29,7 +29,9 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.colorextraction.types.ExtractionType; import com.android.internal.colorextraction.types.Tonal; +import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Iterator; /** * Class to process wallpaper colors and generate a tonal palette based on them. @@ -44,7 +46,7 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener private static final String TAG = "ColorExtractor"; private final SparseArray<GradientColors[]> mGradientColors; - private final ArrayList<OnColorsChangedListener> mOnColorsChangedListeners; + private final ArrayList<WeakReference<OnColorsChangedListener>> mOnColorsChangedListeners; private final Context mContext; private final ExtractionType mExtractionType; private WallpaperColors mSystemColors; @@ -167,8 +169,17 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener } protected void triggerColorsChanged(int which) { - for (OnColorsChangedListener listener: mOnColorsChangedListeners) { - listener.onColorsChanged(this, which); + ArrayList<WeakReference<OnColorsChangedListener>> references = + new ArrayList<>(mOnColorsChangedListeners); + final int size = references.size(); + for (int i = 0; i < size; i++) { + final WeakReference<OnColorsChangedListener> weakReference = references.get(i); + final OnColorsChangedListener listener = weakReference.get(); + if (listener == null) { + mOnColorsChangedListeners.remove(weakReference); + } else { + listener.onColorsChanged(this, which); + } } } @@ -187,11 +198,20 @@ public class ColorExtractor implements WallpaperManager.OnColorsChangedListener } public void addOnColorsChangedListener(@NonNull OnColorsChangedListener listener) { - mOnColorsChangedListeners.add(listener); + mOnColorsChangedListeners.add(new WeakReference<>(listener)); } public void removeOnColorsChangedListener(@NonNull OnColorsChangedListener listener) { - mOnColorsChangedListeners.remove(listener); + ArrayList<WeakReference<OnColorsChangedListener>> references = + new ArrayList<>(mOnColorsChangedListeners); + final int size = references.size(); + for (int i = 0; i < size; i++) { + final WeakReference<OnColorsChangedListener> weakReference = references.get(i); + if (weakReference.get() == listener) { + mOnColorsChangedListeners.remove(weakReference); + break; + } + } } public static class GradientColors { diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index e322acc5d731..47ffa5c5ff82 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -208,7 +208,7 @@ android:icon="@drawable/icon" android:process="com.android.systemui" android:supportsRtl="true" - android:theme="@style/systemui_theme" + android:theme="@style/Theme.SystemUI" android:defaultToDeviceProtectedStorage="true" android:directBootAware="true"> <!-- Keep theme in sync with SystemUIApplication.onCreate(). diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml index b821e7e76c60..9fdb00eebe10 100644 --- a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml +++ b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml @@ -43,7 +43,7 @@ android:layout_height="wrap_content" android:layout_width="280dp" android:layout_gravity="center_horizontal" - android:theme="@style/PasswordTheme" + android:theme="?attr/passwordStyle" > <EditText android:id="@+id/passwordEntry" diff --git a/packages/SystemUI/res-keyguard/values/attrs.xml b/packages/SystemUI/res-keyguard/values/attrs.xml index 802bd308d407..e2ce210efdcb 100644 --- a/packages/SystemUI/res-keyguard/values/attrs.xml +++ b/packages/SystemUI/res-keyguard/values/attrs.xml @@ -41,4 +41,6 @@ <declare-styleable name="CarrierText"> <attr name="allCaps" format="boolean" /> </declare-styleable> + + <attr name="passwordStyle" format="reference" /> </resources> diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml index ea867eed08b4..c6f942356833 100644 --- a/packages/SystemUI/res-keyguard/values/styles.xml +++ b/packages/SystemUI/res-keyguard/values/styles.xml @@ -60,7 +60,13 @@ <item name="android:layout_gravity">center_horizontal|bottom</item> </style> - <style name="PasswordTheme" parent="systemui_theme"> + <style name="PasswordTheme" parent="Theme.SystemUI"> + <item name="android:textColor">?attr/wallpaperTextColor</item> + <item name="android:colorControlNormal">?attr/wallpaperTextColor</item> + <item name="android:colorControlActivated">?attr/wallpaperTextColor</item> + </style> + + <style name="PasswordTheme.Light" parent="Theme.SystemUI.Light"> <item name="android:textColor">?attr/wallpaperTextColor</item> <item name="android:colorControlNormal">?attr/wallpaperTextColor</item> <item name="android:colorControlActivated">?attr/wallpaperTextColor</item> diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml index 056008245563..745d6015d0ff 100644 --- a/packages/SystemUI/res/values/attrs.xml +++ b/packages/SystemUI/res/values/attrs.xml @@ -127,7 +127,7 @@ <attr name="lightIconTheme" format="reference" /> <attr name="darkIconTheme" format="reference" /> - <attr name="wallpaperTextColor" format="color" /> - <attr name="wallpaperTextColorSecondary" format="color" /> + <attr name="wallpaperTextColor" format="reference|color" /> + <attr name="wallpaperTextColorSecondary" format="reference|color" /> </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index daed847c2ac3..a608a8e7c4a7 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -16,7 +16,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android"> - <style name="RecentsTheme" parent="RecentsBase"> + <style name="RecentsTheme" parent="@android:style/Theme.Material"> <!-- NoTitle --> <item name="android:windowNoTitle">true</item> <!-- Misc --> @@ -27,13 +27,6 @@ <item name="android:ambientShadowAlpha">0.35</item> </style> - <!-- OverlayManager might replace this style entirely, use RecentsTheme to set a property - that should exist in both light and dark versions of Recents --> - <style name="RecentsBase" parent="@android:style/Theme.Material"> - <item name="android:textColorPrimaryInverse">@*android:color/primary_text_material_dark</item> - <item name="android:textColorSecondaryInverse">@*android:color/secondary_text_material_dark</item> - </style> - <!-- Recents theme --> <style name="RecentsTheme.Wallpaper"> <item name="android:windowBackground">@*android:color/transparent</item> @@ -41,8 +34,13 @@ <item name="android:windowShowWallpaper">true</item> <item name="android:windowDisablePreview">true</item> <item name="clearAllStyle">@style/ClearAllButtonDefaultMargins</item> - <item name="wallpaperTextColor">?android:attr/textColorPrimaryInverse</item> - <item name="wallpaperTextColorSecondary">?android:attr/textColorSecondaryInverse</item> + <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item> + <item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_dark</item> + </style> + + <style name="RecentsTheme.Wallpaper.Light"> + <item name="wallpaperTextColor">@*android:color/primary_text_material_light</item> + <item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_light</item> </style> <style name="ClearAllButtonDefaultMargins"> @@ -300,21 +298,26 @@ <style name="Animation.StatusBar"> </style> - <!-- Overlay manager may replace this theme --> - <style name="systemui_base" parent="@*android:style/Theme.DeviceDefault.QuickSettings" /> - - <style name="systemui_theme" parent="systemui_base"> + <style name="Theme.SystemUI" parent="@*android:style/Theme.DeviceDefault.QuickSettings"> <item name="lightIconTheme">@style/DualToneLightTheme</item> <item name="darkIconTheme">@style/DualToneDarkTheme</item> - <item name="wallpaperTextColor">?android:attr/textColorPrimaryInverse</item> - <item name="wallpaperTextColorSecondary">?android:attr/textColorSecondaryInverse</item> - <item name="android:colorControlHighlight">?android:attr/textColorSecondaryInverse</item> + <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item> + <item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_dark</item> + <item name="android:colorControlHighlight">@*android:color/primary_text_material_dark</item> <item name="*android:lockPatternStyle">@style/LockPatternStyle</item> + <item name="passwordStyle">@style/PasswordTheme</item> + </style> + + <style name="Theme.SystemUI.Light" parent="@*android:style/Theme.DeviceDefault.QuickSettings"> + <item name="wallpaperTextColor">@*android:color/primary_text_material_light</item> + <item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_light</item> + <item name="android:colorControlHighlight">@*android:color/primary_text_material_light</item> + <item name="passwordStyle">@style/PasswordTheme.Light</item> </style> <style name="LockPatternStyle"> - <item name="*android:regularColor">?android:attr/textColorPrimaryInverse</item> - <item name="*android:successColor">?android:attr/textColorPrimaryInverse</item> + <item name="*android:regularColor">?attr/wallpaperTextColor</item> + <item name="*android:successColor">?attr/wallpaperTextColor</item> <item name="*android:errorColor">?android:attr/colorError</item> </style> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index 165ca2a2d3be..27bc599f7f52 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -21,6 +21,7 @@ import android.app.AlertDialog; import android.app.admin.DevicePolicyManager; import android.content.Context; import android.os.UserHandle; +import android.support.annotation.VisibleForTesting; import android.util.AttributeSet; import android.util.Log; import android.util.Slog; @@ -470,7 +471,8 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe return 0; } - protected int getLayoutIdFor(SecurityMode securityMode) { + @VisibleForTesting + public int getLayoutIdFor(SecurityMode securityMode) { switch (securityMode) { case Pattern: return R.layout.keyguard_pattern_view; case PIN: return R.layout.keyguard_pin_view; diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java index fe6eb4b5acfe..9f2dcd958211 100644 --- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java +++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java @@ -116,7 +116,7 @@ public class SystemUIApplication extends Application implements SysUiServiceProv // Set the application theme that is inherited by all services. Note that setting the // application theme in the manifest does only work for activities. Keep this in sync with // the theme set there. - setTheme(R.style.systemui_theme); + setTheme(R.style.Theme_SystemUI); SystemUIFactory.createFromConfig(this); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index f2ea6a683e95..c0550b5c52e6 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -20,11 +20,11 @@ import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.TaskStackBuilder; +import android.app.WallpaperManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.net.Uri; import android.os.Bundle; @@ -41,12 +41,15 @@ import android.view.ViewTreeObserver.OnPreDrawListener; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; +import com.android.internal.colorextraction.ColorExtractor; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.keyguard.LatencyTracker; import com.android.systemui.DejankUtils; +import com.android.systemui.Dependency; import com.android.systemui.Interpolators; import com.android.systemui.R; +import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent; import com.android.systemui.recents.events.activity.ConfigurationChangedEvent; @@ -100,7 +103,8 @@ import java.util.List; /** * The main Recents activity that is started from RecentsComponent. */ -public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreDrawListener { +public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreDrawListener, + ColorExtractor.OnColorsChangedListener { private final static String TAG = "RecentsActivity"; private final static boolean DEBUG = false; @@ -129,6 +133,10 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD private DozeTrigger mIterateTrigger; private final UserInteractionEvent mUserInteractionEvent = new UserInteractionEvent(); + // Theme and colors + private SysuiColorExtractor mColorExtractor; + private boolean mUsingDarkText; + /** * A common Runnable to finish Recents by launching Home with an animation depending on the * last activity launch state. Generally we always launch home when we exit Recents rather than @@ -329,6 +337,14 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD mPackageMonitor = new RecentsPackageMonitor(); mPackageMonitor.register(this); + // Select theme based on wallpaper colors + mColorExtractor = Dependency.get(SysuiColorExtractor.class); + mColorExtractor.addOnColorsChangedListener(this); + mUsingDarkText = mColorExtractor.getColors(ColorExtractor.TYPE_DARK, + WallpaperManager.FLAG_SYSTEM, true).supportsDarkText(); + setTheme(mUsingDarkText ? R.style.RecentsTheme_Wallpaper_Light + : R.style.RecentsTheme_Wallpaper); + // Set the Recents layout setContentView(R.layout.recents); takeKeyEvents(true); @@ -375,13 +391,37 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true)); MetricsLogger.visible(this, MetricsEvent.OVERVIEW_ACTIVITY); - // Make sure we have the right gradient and we're listening for update events - mRecentsView.onStart(); + // Getting system scrim colors ignoring wallpaper visibility since it should never be grey. + ColorExtractor.GradientColors systemColors = mColorExtractor.getColors( + ColorExtractor.TYPE_DARK, WallpaperManager.FLAG_SYSTEM, true); + // We don't want to interpolate colors because we're defining the initial state. + // Gradient should be set/ready when you open "Recents". + mRecentsView.setScrimColors(systemColors, false); + // Notify of the next draw mRecentsView.getViewTreeObserver().addOnPreDrawListener(mRecentsDrawnEventListener); } @Override + public void onColorsChanged(ColorExtractor colorExtractor, int which) { + if ((which & WallpaperManager.FLAG_SYSTEM) != 0) { + // Recents doesn't care about the wallpaper being visible or not, it always + // wants to scrim with wallpaper colors + ColorExtractor.GradientColors colors = mColorExtractor.getColors( + WallpaperManager.FLAG_SYSTEM, + ColorExtractor.TYPE_DARK, true /* ignoreVis */); + boolean darkText = colors.supportsDarkText(); + if (darkText != mUsingDarkText) { + mUsingDarkText = darkText; + setTheme(mUsingDarkText ? R.style.RecentsTheme_Wallpaper_Light + : R.style.RecentsTheme_Wallpaper); + mRecentsView.reevaluateStyles(); + } + mRecentsView.setScrimColors(colors, true /* animated */); + } + } + + @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); @@ -483,12 +523,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD mLastConfig.orientation != newDeviceConfiguration.orientation, mLastConfig.densityDpi != newDeviceConfiguration.densityDpi, numStackTasks > 0)); - int configDiff = mLastConfig.updateFrom(newDeviceConfiguration); - - // Recreate activity if an overlay was enabled/disabled - if ((configDiff & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) { - recreate(); - } + mLastConfig.updateFrom(newDeviceConfiguration); } @Override @@ -508,9 +543,6 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD MetricsLogger.hidden(this, MetricsEvent.OVERVIEW_ACTIVITY); Recents.getTaskLoader().getHighResThumbnailLoader().setVisible(false); - // We don't need to update the gradient when we're not visible - mRecentsView.onStop(); - if (!isChangingConfigurations()) { // Workaround for b/22542869, if the RecentsActivity is started again, but without going // through SystemUI, we need to reset the config launch flags to ensure that we do not diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java index fd37b17f3cd0..8e094813257c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -21,13 +21,12 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import android.animation.Animator; import android.animation.ObjectAnimator; import android.app.ActivityOptions.OnAnimationStartedListener; -import android.app.WallpaperColors; -import android.app.WallpaperManager; import android.content.Context; +import android.content.res.ColorStateList; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.PointF; import android.graphics.Rect; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.util.ArraySet; import android.util.AttributeSet; @@ -43,12 +42,12 @@ import android.widget.FrameLayout; import android.widget.TextView; import com.android.internal.colorextraction.ColorExtractor; +import com.android.internal.colorextraction.drawable.GradientDrawable; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.systemui.Dependency; +import com.android.settingslib.Utils; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsActivity; import com.android.systemui.recents.RecentsActivityLaunchState; @@ -83,8 +82,6 @@ import com.android.systemui.stackdivider.WindowManagerProxy; import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.phone.ScrimController; -import com.android.internal.colorextraction.drawable.GradientDrawable; - import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; @@ -93,7 +90,7 @@ import java.util.List; * This view is the the top level layout that contains TaskStacks (which are laid out according * to their SpaceNode bounds. */ -public class RecentsView extends FrameLayout implements ColorExtractor.OnColorsChangedListener { +public class RecentsView extends FrameLayout { private static final String TAG = "RecentsView"; @@ -107,6 +104,9 @@ public class RecentsView extends FrameLayout implements ColorExtractor.OnColorsC private TaskStackView mTaskStackView; private TextView mStackActionButton; private TextView mEmptyView; + private final float mStackButtonShadowRadius; + private final PointF mStackButtonShadowDistance; + private final int mStackButtonShadowColor; private boolean mAwaitingFirstLayout = true; private boolean mLastTaskLaunchedWasFreeform; @@ -117,7 +117,6 @@ public class RecentsView extends FrameLayout implements ColorExtractor.OnColorsC private float mBusynessFactor; private GradientDrawable mBackgroundScrim; - private final SysuiColorExtractor mColorExtractor; private Animator mBackgroundScrimAnimator; private RecentsTransitionHelper mTransitionHelper; @@ -148,29 +147,51 @@ public class RecentsView extends FrameLayout implements ColorExtractor.OnColorsC mFlingAnimationUtils = new FlingAnimationUtils(context, 0.3f); mBackgroundScrim = new GradientDrawable(context); mBackgroundScrim.setCallback(this); - mColorExtractor = Dependency.get(SysuiColorExtractor.class); - LayoutInflater inflater = LayoutInflater.from(context); + boolean usingDarkText = Color.luminance( + Utils.getColorAttr(mContext, R.attr.wallpaperTextColor)) < 0.5f; + LayoutInflater inflater = LayoutInflater.from(context); mEmptyView = (TextView) inflater.inflate(R.layout.recents_empty, this, false); addView(mEmptyView); - boolean usingDarkText = - Color.luminance(mEmptyView.getTextColors().getDefaultColor()) < 0.5f; if (RecentsDebugFlags.Static.EnableStackActionButton) { + if (mStackActionButton != null) { + removeView(mStackActionButton); + } mStackActionButton = (TextView) inflater.inflate(R.layout.recents_stack_action_button, this, false); - mStackActionButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - EventBus.getDefault().send(new DismissAllTaskViewsEvent()); - } - }); - // Disable black shadow if text color is already dark. + mStackActionButton.setOnClickListener( + v -> EventBus.getDefault().send(new DismissAllTaskViewsEvent())); + + mStackButtonShadowRadius = mStackActionButton.getShadowRadius(); + mStackButtonShadowDistance = new PointF(mStackActionButton.getShadowDx(), + mStackActionButton.getShadowDy()); + mStackButtonShadowColor = mStackActionButton.getShadowColor(); + addView(mStackActionButton); + } + + reevaluateStyles(); + } + + public void reevaluateStyles() { + int textColor = Utils.getColorAttr(mContext, R.attr.wallpaperTextColor); + boolean usingDarkText = Color.luminance(textColor) < 0.5f; + + mEmptyView.setTextColor(textColor); + mEmptyView.setCompoundDrawableTintList(new ColorStateList(new int[][]{ + {android.R.attr.state_enabled}}, new int[]{textColor})); + + if (mStackActionButton != null) { + mStackActionButton.setTextColor(textColor); + // Enable/disable shadow if text color is already dark. if (usingDarkText) { mStackActionButton.setShadowLayer(0, 0, 0, 0); + } else { + mStackActionButton.setShadowLayer(mStackButtonShadowRadius, + mStackButtonShadowDistance.x, mStackButtonShadowDistance.y, + mStackButtonShadowColor); } - addView(mStackActionButton); } // Let's also require dark status and nav bars if the text is dark @@ -369,6 +390,16 @@ public class RecentsView extends FrameLayout implements ColorExtractor.OnColorsC } } + /** + * Set the color of the scrim. + * + * @param scrimColors Colors to use. + * @param animated Interpolate colors if true. + */ + public void setScrimColors(ColorExtractor.GradientColors scrimColors, boolean animated) { + mBackgroundScrim.setColors(scrimColors, animated); + } + @Override protected void onAttachedToWindow() { EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1); @@ -888,29 +919,4 @@ public class RecentsView extends FrameLayout implements ColorExtractor.OnColorsC mTaskStackView.dump(innerPrefix, writer); } } - - @Override - public void onColorsChanged(ColorExtractor colorExtractor, int which) { - if ((which & WallpaperManager.FLAG_SYSTEM) != 0) { - // Recents doesn't care about the wallpaper being visible or not, it always - // wants to scrim with wallpaper colors - mBackgroundScrim.setColors( - mColorExtractor.getColors(WallpaperManager.FLAG_SYSTEM, - ColorExtractor.TYPE_DARK, true)); - } - } - - public void onStart() { - mColorExtractor.addOnColorsChangedListener(this); - // Getting system scrim colors ignoring wallpaper visibility since it should never be grey. - ColorExtractor.GradientColors systemColors = mColorExtractor.getColors( - ColorExtractor.TYPE_DARK, WallpaperManager.FLAG_SYSTEM, true); - // We don't want to interpolate colors because we're defining the initial state. - // Gradient should be set/ready when you open "Recents". - mBackgroundScrim.setColors(systemColors, false); - } - - public void onStop() { - mColorExtractor.removeOnColorsChangedListener(this); - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java index 543666407fb9..d7c6443a6c3b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar; +import android.annotation.ColorInt; import android.content.Context; import android.content.res.Configuration; import android.util.AttributeSet; @@ -46,6 +47,10 @@ public class DismissView extends StackScrollerDecorView { mDismissButton = (DismissViewButton) findContentView(); } + public void setTextColor(@ColorInt int color) { + mDismissButton.setTextColor(color); + } + public void setOnButtonClickListener(OnClickListener listener) { mContent.setOnClickListener(listener); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java index 92b0890a5d2b..58adde269758 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar; +import android.annotation.ColorInt; import android.content.Context; import android.content.res.Configuration; import android.util.AttributeSet; @@ -45,6 +46,10 @@ public class EmptyShadeView extends StackScrollerDecorView { return findViewById(R.id.no_notifications); } + public void setTextColor(@ColorInt int color) { + mEmptyText.setTextColor(color); + } + @Override protected void onFinishInflate() { super.onFinishInflate(); 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 75a27680287b..bc37d831a828 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -978,9 +978,6 @@ public class StatusBar extends SystemUI implements DemoMode, Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(this); Dependency.get(ConfigurationController.class).addCallback(this); - - // Make sure that we're using the correct theme - onOverlayChanged(); } protected void createIconController() { @@ -993,6 +990,7 @@ public class StatusBar extends SystemUI implements DemoMode, final Context context = mContext; updateDisplaySize(); // populates mDisplayMetrics updateResources(); + updateTheme(); inflateStatusBarWindow(context); mStatusBarWindow.setService(this); @@ -1200,7 +1198,6 @@ public class StatusBar extends SystemUI implements DemoMode, }); } - PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); if (!pm.isScreenOn()) { mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF)); @@ -1305,14 +1302,14 @@ public class StatusBar extends SystemUI implements DemoMode, reevaluateStyles(); } - public void onOverlayChanged() { + private void reinflateViews() { reevaluateStyles(); // Clock and bottom icons mNotificationPanel.onOverlayChanged(); - + // The status bar on the keyguard is a special layout. + mKeyguardStatusBar.onOverlayChanged(); // Recreate Indication controller because internal references changed - // TODO: unregister callbacks before recreating mKeyguardIndicationController = SystemUIFactory.getInstance().createKeyguardIndicationController(mContext, mStatusBarWindow.findViewById(R.id.keyguard_indication_area), @@ -2857,17 +2854,6 @@ public class StatusBar extends SystemUI implements DemoMode, updateTheme(); } - public boolean isUsingDarkText() { - OverlayInfo themeInfo = null; - try { - themeInfo = mOverlayManager.getOverlayInfo("com.android.systemui.theme.lightwallpaper", - mCurrentUserId); - } catch (RemoteException e) { - e.printStackTrace(); - } - return themeInfo != null && themeInfo.isEnabled(); - } - public boolean isUsingDarkTheme() { OverlayInfo themeInfo = null; try { @@ -4566,24 +4552,13 @@ public class StatusBar extends SystemUI implements DemoMode, * Switches theme from light to dark and vice-versa. */ private void updateTheme() { + final boolean inflated = mStackScroller != null; - int which; - if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { - which = WallpaperManager.FLAG_LOCK; - } else { - which = WallpaperManager.FLAG_SYSTEM; - } - - // Gradient defines if text color should be light or dark. - final boolean useDarkText = mColorExtractor.getColors(which, true /* ignoreVisibility */) - .supportsDarkText(); - // And wallpaper defines if QS should be light or dark. + // The system wallpaper defines if QS should be light or dark. WallpaperColors systemColors = mColorExtractor .getWallpaperColors(WallpaperManager.FLAG_SYSTEM); final boolean useDarkTheme = systemColors != null && (systemColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0; - - // Enable/disable dark UI. if (isUsingDarkTheme() != useDarkTheme) { try { mOverlayManager.setEnabled("com.android.systemui.theme.dark", @@ -4592,18 +4567,33 @@ public class StatusBar extends SystemUI implements DemoMode, Log.w(TAG, "Can't change theme", e); } } - // Enable/disable dark text overlay. - if (isUsingDarkText() != useDarkText) { - try { - mOverlayManager.setEnabled("com.android.systemui.theme.lightwallpaper", - useDarkText, mCurrentUserId); - } catch (RemoteException e) { - Log.w(TAG, "Can't change theme", e); + + // Lock wallpaper defines the color of the majority of the views, hence we'll use it + // to set our default theme. + final boolean lockDarkText = mColorExtractor.getColors(WallpaperManager.FLAG_LOCK, true + /* ignoreVisibility */).supportsDarkText(); + final int themeResId = lockDarkText ? R.style.Theme_SystemUI_Light : R.style.Theme_SystemUI; + if (mContext.getThemeResId() != themeResId) { + mContext.setTheme(themeResId); + if (inflated) { + reinflateViews(); } } - // Make sure we have the correct navbar/statusbar colors. - mStatusBarWindowManager.setKeyguardDark(useDarkText); + if (inflated) { + int which; + if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) { + which = WallpaperManager.FLAG_LOCK; + } else { + which = WallpaperManager.FLAG_SYSTEM; + } + final boolean useDarkText = mColorExtractor.getColors(which, + true /* ignoreVisibility */).supportsDarkText(); + mStackScroller.updateDecorViews(useDarkText); + + // Make sure we have the correct navbar/statusbar colors. + mStatusBarWindowManager.setKeyguardDark(useDarkText); + } } private void updateDozingState() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 42cebe2632bb..4bbe895da7ca 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -23,6 +23,7 @@ import android.animation.PropertyValuesHolder; import android.animation.TimeAnimator; import android.animation.ValueAnimator; import android.animation.ValueAnimator.AnimatorUpdateListener; +import android.annotation.ColorInt; import android.annotation.FloatRange; import android.annotation.Nullable; import android.content.Context; @@ -44,6 +45,7 @@ import android.util.FloatProperty; import android.util.Log; import android.util.Pair; import android.util.Property; +import android.view.ContextThemeWrapper; import android.view.InputDevice; import android.view.MotionEvent; import android.view.VelocityTracker; @@ -61,6 +63,7 @@ import android.widget.ScrollView; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settingslib.Utils; import com.android.systemui.ExpandHelper; import com.android.systemui.Interpolators; import com.android.systemui.R; @@ -363,6 +366,7 @@ public class NotificationStackScrollLayout extends ViewGroup return object.getBackgroundFadeAmount(); } }; + private boolean mUsingLightTheme; private boolean mQsExpanded; private boolean mForwardScrollable; private boolean mBackwardScrollable; @@ -3653,6 +3657,23 @@ public class NotificationStackScrollLayout extends ViewGroup mTmpSortedChildren.clear(); } + /** + * Update colors of "dismiss" and "empty shade" views. + * + * @param lightTheme True if light theme should be used. + */ + public void updateDecorViews(boolean lightTheme) { + if (lightTheme == mUsingLightTheme) { + return; + } + mUsingLightTheme = lightTheme; + Context context = new ContextThemeWrapper(mContext, + lightTheme ? R.style.Theme_SystemUI_Light : R.style.Theme_SystemUI); + final int textColor = Utils.getColorAttr(context, R.attr.wallpaperTextColor); + mDismissView.setTextColor(textColor); + mEmptyShadeView.setTextColor(textColor); + } + public void goToFullShade(long delay) { if (mDismissView != null) { mDismissView.setInvisible(); diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml index f24e7b56bfc4..03f3c56aab73 100644 --- a/packages/SystemUI/tests/AndroidManifest.xml +++ b/packages/SystemUI/tests/AndroidManifest.xml @@ -39,6 +39,8 @@ <uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.GET_APP_OPS_STATS" /> <uses-permission android:name="android.permission.BLUETOOTH" /> + <uses-permission android:name="android.permission.TRUST_LISTENER" /> + <uses-permission android:name="android.permission.USE_FINGERPRINT" /> <application> <uses-library android:name="android.test.runner" /> diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java new file mode 100644 index 000000000000..fcf327b5d1fa --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java @@ -0,0 +1,58 @@ +/* + * 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.keyguard; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import android.content.Context; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.test.UiThreadTest; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; + +import com.android.systemui.SysuiTestCase; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class KeyguardSecurityContainerTest extends SysuiTestCase { + + @UiThreadTest + @Test + public void showSecurityScreen_canInflateAllModes() { + KeyguardSecurityContainer keyguardSecurityContainer = + new KeyguardSecurityContainer(getContext()); + + Context context = getContext(); + + for (int theme : new int[] {R.style.Theme_SystemUI, R.style.Theme_SystemUI_Light}) { + context.setTheme(theme); + final LayoutInflater inflater = LayoutInflater.from(context); + KeyguardSecurityModel.SecurityMode[] modes = + KeyguardSecurityModel.SecurityMode.values(); + for (KeyguardSecurityModel.SecurityMode mode : modes) { + final int resId = keyguardSecurityContainer.getLayoutIdFor(mode); + if (resId == 0) { + continue; + } + inflater.inflate(resId, null /* root */, false /* attach */); + } + } + } +}
\ No newline at end of file diff --git a/packages/overlays/SysuiLightWallpaperThemeOverlay/Android.mk b/packages/overlays/SysuiLightWallpaperThemeOverlay/Android.mk deleted file mode 100644 index 4782a166146b..000000000000 --- a/packages/overlays/SysuiLightWallpaperThemeOverlay/Android.mk +++ /dev/null @@ -1,13 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_RRO_THEME := SysuiLightWallpaperTheme -LOCAL_CERTIFICATE := platform - -LOCAL_SRC_FILES := $(call all-subdir-java-files) - -LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res - -LOCAL_PACKAGE_NAME := SysuiLightWallpaperThemeOverlay - -include $(BUILD_RRO_PACKAGE) diff --git a/packages/overlays/SysuiLightWallpaperThemeOverlay/AndroidManifest.xml b/packages/overlays/SysuiLightWallpaperThemeOverlay/AndroidManifest.xml deleted file mode 100644 index 0a8749c64ea2..000000000000 --- a/packages/overlays/SysuiLightWallpaperThemeOverlay/AndroidManifest.xml +++ /dev/null @@ -1,8 +0,0 @@ -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.systemui.theme.lightwallpaper" - android:versionCode="1" - android:versionName="1.0"> - <overlay android:targetPackage="com.android.systemui" android:priority="2"/> - - <application android:label="@string/sysui_overlay_light" android:hasCode="false"/> -</manifest> diff --git a/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/strings.xml b/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/strings.xml deleted file mode 100644 index acc3d16610ec..000000000000 --- a/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/strings.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/** - * 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. - */ ---> -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - - <string name="sysui_overlay_light">Light</string> - -</resources> - diff --git a/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/styles.xml b/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/styles.xml deleted file mode 100644 index 53912b50df00..000000000000 --- a/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/styles.xml +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources> - <style name="systemui_base" parent="@*android:style/Theme.DeviceDefault.QuickSettings"> - <item name="android:textColorPrimaryInverse">@*android:color/primary_text_material_light</item> - <item name="android:textColorSecondaryInverse">@*android:color/secondary_text_material_light</item> - </style> - - <style name="RecentsBase" parent="@android:style/Theme.Material"> - <item name="android:textColorPrimaryInverse">@*android:color/primary_text_material_light</item> - <item name="android:textColorSecondaryInverse">@*android:color/secondary_text_material_light</item> - </style> -</resources>
\ No newline at end of file diff --git a/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java b/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java index 0060901578cd..cb6a83d2644b 100644 --- a/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java +++ b/tests/Internal/src/com/android/internal/colorextraction/ColorExtractorTest.java @@ -16,12 +16,14 @@ package com.android.internal.colorextraction; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.mockito.Mockito.any; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import android.app.WallpaperColors; import android.app.WallpaperManager; import android.content.Context; import android.graphics.Color; @@ -29,7 +31,6 @@ import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; -import com.android.internal.colorextraction.ColorExtractor; import com.android.internal.colorextraction.ColorExtractor.GradientColors; import com.android.internal.colorextraction.types.ExtractionType; import com.android.internal.colorextraction.types.Tonal; @@ -78,10 +79,10 @@ public class ColorExtractorTest { ExtractionType type = (inWallpaperColors, outGradientColorsNormal, outGradientColorsDark, outGradientColorsExtraDark) -> { - outGradientColorsNormal.set(colorsExpectedNormal); - outGradientColorsDark.set(colorsExpectedDark); - outGradientColorsExtraDark.set(colorsExpectedExtraDark); - }; + outGradientColorsNormal.set(colorsExpectedNormal); + outGradientColorsDark.set(colorsExpectedDark); + outGradientColorsExtraDark.set(colorsExpectedExtraDark); + }; ColorExtractor extractor = new ColorExtractor(mContext, type); GradientColors colors = extractor.getColors(WallpaperManager.FLAG_SYSTEM, @@ -92,4 +93,22 @@ public class ColorExtractorTest { colors = extractor.getColors(WallpaperManager.FLAG_SYSTEM, ColorExtractor.TYPE_EXTRA_DARK); assertEquals("Extracted colors not being used!", colors, colorsExpectedExtraDark); } + + @Test + public void addOnColorsChangedListener_invokesListener() { + ColorExtractor.OnColorsChangedListener mockedListeners = + mock(ColorExtractor.OnColorsChangedListener.class); + ColorExtractor extractor = new ColorExtractor(mContext, new Tonal(mContext)); + extractor.addOnColorsChangedListener(mockedListeners); + + extractor.onColorsChanged(new WallpaperColors(Color.valueOf(Color.RED), null, null), + WallpaperManager.FLAG_LOCK); + verify(mockedListeners, times(1)).onColorsChanged(any(), + eq(WallpaperManager.FLAG_LOCK)); + + extractor.removeOnColorsChangedListener(mockedListeners); + extractor.onColorsChanged(new WallpaperColors(Color.valueOf(Color.RED), null, null), + WallpaperManager.FLAG_LOCK); + verifyNoMoreInteractions(mockedListeners); + } } |