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
This commit is contained in:
Lucas Dupin
2017-07-17 15:45:06 -07:00
parent f5c3922645
commit e17ce5286f
22 changed files with 308 additions and 194 deletions

View File

@@ -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 {

View File

@@ -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().

View File

@@ -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"

View File

@@ -41,4 +41,6 @@
<declare-styleable name="CarrierText">
<attr name="allCaps" format="boolean" />
</declare-styleable>
<attr name="passwordStyle" format="reference" />
</resources>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;

View File

@@ -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);

View File

@@ -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,12 +391,36 @@ 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

View File

@@ -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);
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);
}
}

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -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() {

View File

@@ -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();

View File

@@ -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" />

View File

@@ -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 */);
}
}
}
}

View File

@@ -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)

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);
}
}