diff options
12 files changed, 732 insertions, 0 deletions
diff --git a/packages/SystemUI/res-keyguard/drawable/bubble_hour_hand.xml b/packages/SystemUI/res-keyguard/drawable/bubble_hour_hand.xml new file mode 100644 index 000000000000..d3c3a518f6ac --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/bubble_hour_hand.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="200dp" + android:width="200dp" + android:viewportHeight="100" + android:viewportWidth="100"> + <path + android:fillColor="#000000" + android:pathData="M50.082,14.199m-13.985,0a13.985,13.985 0,1 1,27.97 0a13.985,13.985 0,1 1,-27.97 0"/> +</vector> diff --git a/packages/SystemUI/res-keyguard/drawable/bubble_minute_hand.xml b/packages/SystemUI/res-keyguard/drawable/bubble_minute_hand.xml new file mode 100644 index 000000000000..a4417fb65da4 --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/bubble_minute_hand.xml @@ -0,0 +1,9 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="200dp" + android:width="200dp" + android:viewportHeight="100" + android:viewportWidth="100" > + <path + android:fillColor="#000000" + android:pathData="M50.082,0.025L50.082,0.025A13.985,15.63 0,0 1,64.067 15.656L64.067,49.029A13.985,15.63 0,0 1,50.082 64.659L50.082,64.659A13.985,15.63 0,0 1,36.097 49.029L36.097,15.656A13.985,15.63 0,0 1,50.082 0.025z"/> +</vector> diff --git a/packages/SystemUI/res-keyguard/layout/bubble_clock.xml b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml new file mode 100644 index 000000000000..0d72657bb2df --- /dev/null +++ b/packages/SystemUI/res-keyguard/layout/bubble_clock.xml @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<com.android.keyguard.clock.ClockLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + > + <TextClock + android:id="@+id/digital_clock" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:letterSpacing="0.03" + android:singleLine="true" + style="@style/widget_big" + android:format12Hour="@string/keyguard_widget_12_hours_format" + android:format24Hour="@string/keyguard_widget_24_hours_format" + /> + <com.android.keyguard.clock.ImageClock + android:id="@+id/analog_clock" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + > + <ImageView + android:id="@+id/minute_hand" + android:layout_width="300dp" + android:layout_height="300dp" + android:src="@drawable/bubble_minute_hand" + android:tint="@color/bubbleMinuteHandColor" + /> + <ImageView + android:id="@+id/hour_hand" + android:layout_width="300dp" + android:layout_height="300dp" + android:src="@drawable/bubble_hour_hand" + android:tint="@color/bubbleHourHandColor" + /> + </com.android.keyguard.clock.ImageClock> +</com.android.keyguard.clock.ClockLayout> diff --git a/packages/SystemUI/res-keyguard/layout/digital_clock.xml b/packages/SystemUI/res-keyguard/layout/digital_clock.xml new file mode 100644 index 000000000000..cf4a573834dd --- /dev/null +++ b/packages/SystemUI/res-keyguard/layout/digital_clock.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 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. + --> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:layout_alignParentTop="true"> + <TextClock + android:id="@+id/lock_screen_clock" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:letterSpacing="0.03" + android:singleLine="true" + style="@style/widget_big" + android:format12Hour="@string/keyguard_widget_12_hours_format" + android:format24Hour="@string/keyguard_widget_24_hours_format" /> + /> +</FrameLayout> + diff --git a/packages/SystemUI/res-keyguard/values/colors.xml b/packages/SystemUI/res-keyguard/values/colors.xml new file mode 100644 index 000000000000..7a849ebd481d --- /dev/null +++ b/packages/SystemUI/res-keyguard/values/colors.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2019 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> + <!-- Default color for hour hand of Bubble clock. --> + <color name="bubbleHourHandColor">#C97343</color> + <!-- Default color for minute hand of Bubble clock. --> + <color name="bubbleMinuteHandColor">#F5C983</color> +</resources> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java index 17cc1d57582c..efa43c618996 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java @@ -1,9 +1,15 @@ package com.android.keyguard; +import android.content.ContentResolver; import android.content.Context; +import android.database.ContentObserver; import android.graphics.Paint; import android.graphics.Paint.Style; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; import android.util.AttributeSet; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; @@ -12,6 +18,7 @@ import android.widget.TextClock; import androidx.annotation.VisibleForTesting; +import com.android.keyguard.clock.BubbleClockController; import com.android.systemui.Dependency; import com.android.systemui.plugins.ClockPlugin; import com.android.systemui.statusbar.StatusBarState; @@ -19,13 +26,19 @@ import com.android.systemui.statusbar.StatusBarStateController; import com.android.systemui.statusbar.policy.ExtensionController; import com.android.systemui.statusbar.policy.ExtensionController.Extension; +import java.util.Objects; import java.util.TimeZone; import java.util.function.Consumer; +import java.util.function.Supplier; /** * Switch to show plugin clock when plugin is connected, otherwise it will show default clock. */ public class KeyguardClockSwitch extends RelativeLayout { + + private LayoutInflater mLayoutInflater; + + private final ContentResolver mContentResolver; /** * Optional/alternative clock injected via plugin. */ @@ -79,12 +92,25 @@ public class KeyguardClockSwitch extends RelativeLayout { } }; + private final ContentObserver mContentObserver = + new ContentObserver(new Handler(Looper.getMainLooper())) { + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + if (mClockExtension != null) { + mClockExtension.reload(); + } + } + }; + public KeyguardClockSwitch(Context context) { this(context, null); } public KeyguardClockSwitch(Context context, AttributeSet attrs) { super(context, attrs); + mLayoutInflater = LayoutInflater.from(context); + mContentResolver = context.getContentResolver(); } @Override @@ -101,7 +127,22 @@ public class KeyguardClockSwitch extends RelativeLayout { mClockExtension = Dependency.get(ExtensionController.class).newExtension(ClockPlugin.class) .withPlugin(ClockPlugin.class) .withCallback(mClockPluginConsumer) + // Using withDefault even though this isn't the default as a workaround. + // ExtensionBulider doesn't provide the ability to supply a ClockPlugin + // instance based off of the value of a setting. Since multiple "default" + // can be provided, using a supplier that changes the settings value. + // A null return will cause Extension#reload to look at the next "default" + // supplier. + .withDefault( + new SettingsGattedSupplier( + mContentResolver, + Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE, + BubbleClockController.class.getName(), + () -> BubbleClockController.build(mLayoutInflater))) .build(); + mContentResolver.registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE), + false, mContentObserver); Dependency.get(StatusBarStateController.class).addCallback(mStateListener); } @@ -109,6 +150,7 @@ public class KeyguardClockSwitch extends RelativeLayout { protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mClockExtension.destroy(); + mContentResolver.unregisterContentObserver(mContentObserver); Dependency.get(StatusBarStateController.class).removeCallback(mStateListener); } @@ -262,4 +304,44 @@ public class KeyguardClockSwitch extends RelativeLayout { StatusBarStateController.StateListener getStateListener() { return mStateListener; } + + /** + * Supplier that only gets an instance when a settings value matches expected value. + */ + private static class SettingsGattedSupplier implements Supplier<ClockPlugin> { + + private final ContentResolver mContentResolver; + private final String mKey; + private final String mValue; + private final Supplier<ClockPlugin> mSupplier; + + /** + * Constructs a supplier that changes secure setting key against value. + * + * @param contentResolver Used to look up settings value. + * @param key Settings key. + * @param value If the setting matches this values that get supplies a ClockPlugin + * instance. + * @param supplier Supplier of ClockPlugin instance, only used if the setting + * matches value. + */ + SettingsGattedSupplier(ContentResolver contentResolver, String key, String value, + Supplier<ClockPlugin> supplier) { + mContentResolver = contentResolver; + mKey = key; + mValue = value; + mSupplier = supplier; + } + + /** + * Returns null if the settings value doesn't match the expected value. + * + * A null return causes Extension#reload to skip this supplier and move to the next. + */ + @Override + public ClockPlugin get() { + final String currentValue = Settings.Secure.getString(mContentResolver, mKey); + return Objects.equals(currentValue, mValue) ? mSupplier.get() : null; + } + } } diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java new file mode 100644 index 000000000000..db6127f1d573 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2019 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.clock; + +import android.graphics.Paint.Style; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextClock; + +import com.android.keyguard.R; +import com.android.systemui.plugins.ClockPlugin; + +import java.util.TimeZone; + +/** + * Controller for Bubble clock that can appear on lock screen and AOD. + */ +public class BubbleClockController implements ClockPlugin { + + /** + * Custom clock shown on AOD screen and behind stack scroller on lock. + */ + private View mView; + private TextClock mDigitalClock; + private ImageClock mAnalogClock; + + /** + * Small clock shown on lock screen above stack scroller. + */ + private View mLockClockContainer; + private TextClock mLockClock; + + /** + * Controller for transition to dark state. + */ + private CrossFadeDarkController mDarkController; + + private BubbleClockController() { } + + /** + * Create a BubbleClockController instance. + * + * @param layoutInflater Inflater used to inflate custom clock views. + */ + public static BubbleClockController build(LayoutInflater layoutInflater) { + BubbleClockController controller = new BubbleClockController(); + controller.createViews(layoutInflater); + return controller; + } + + private void createViews(LayoutInflater layoutInflater) { + mView = layoutInflater.inflate(R.layout.bubble_clock, null); + mDigitalClock = (TextClock) mView.findViewById(R.id.digital_clock); + mAnalogClock = (ImageClock) mView.findViewById(R.id.analog_clock); + + mLockClockContainer = layoutInflater.inflate(R.layout.digital_clock, null); + mLockClock = (TextClock) mLockClockContainer.findViewById(R.id.lock_screen_clock); + mLockClock.setVisibility(View.GONE); + + mDarkController = new CrossFadeDarkController(mDigitalClock, mLockClock); + } + + @Override + public View getView() { + return mLockClockContainer; + } + + @Override + public View getBigClockView() { + return mView; + } + + @Override + public void setStyle(Style style) {} + + @Override + public void setTextColor(int color) { + mLockClock.setTextColor(color); + mDigitalClock.setTextColor(color); + } + + @Override + public void dozeTimeTick() { + mAnalogClock.onTimeChanged(); + } + + @Override + public void setDarkAmount(float darkAmount) { + mDarkController.setDarkAmount(darkAmount); + } + + @Override + public void onTimeZoneChanged(TimeZone timeZone) { + mAnalogClock.onTimeZoneChanged(timeZone); + } + + @Override + public boolean shouldShowStatusArea() { + return false; + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java new file mode 100644 index 000000000000..5aa566848732 --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2019 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.clock; + +import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset; + +import android.content.Context; +import android.content.res.Resources; +import android.util.AttributeSet; +import android.view.View; +import android.widget.FrameLayout; + +import com.android.keyguard.R; + +/** + * Positions clock faces (analog, digital, typographic) and handles pixel shifting + * to prevent screen burn-in. + */ +public class ClockLayout extends FrameLayout { + + /** + * Clock face views. + */ + private View mDigitalClock; + private View mAnalogClock; + + /** + * Pixel shifting amplitidues used to prevent screen burn-in. + */ + private int mBurnInPreventionOffsetX; + private int mBurnInPreventionOffsetY; + + public ClockLayout(Context context) { + this(context, null); + } + + public ClockLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ClockLayout(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mDigitalClock = findViewById(R.id.digital_clock); + mAnalogClock = findViewById(R.id.analog_clock); + + // Get pixel shifting X, Y amplitudes from resources. + Resources resources = getResources(); + mBurnInPreventionOffsetX = resources.getDimensionPixelSize( + R.dimen.burn_in_prevention_offset_x); + mBurnInPreventionOffsetY = resources.getDimensionPixelSize( + R.dimen.burn_in_prevention_offset_y); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + + final float offsetX = getBurnInOffset(mBurnInPreventionOffsetX, true); + final float offsetY = getBurnInOffset(mBurnInPreventionOffsetY, false); + + // Put digital clock in two left corner of the screen. + if (mDigitalClock != null) { + mDigitalClock.setX(0.1f * getWidth() + offsetX); + mDigitalClock.setY(0.1f * getHeight() + offsetY); + } + + // Put the analog clock in the middle of the screen. + if (mAnalogClock != null) { + mAnalogClock.setX(Math.max(0f, 0.5f * (getWidth() - mAnalogClock.getWidth())) + + offsetX); + mAnalogClock.setY(Math.max(0f, 0.5f * (getHeight() - mAnalogClock.getHeight())) + + offsetY); + } + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/clock/CrossFadeDarkController.java b/packages/SystemUI/src/com/android/keyguard/clock/CrossFadeDarkController.java new file mode 100644 index 000000000000..3c3f4759614b --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/clock/CrossFadeDarkController.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2019 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.clock; + +import android.view.View; + +/** + * Controls transition to dark state by cross fading between views. + */ +final class CrossFadeDarkController { + + private final View mFadeInView; + private final View mFadeOutView; + + /** + * Creates a new controller that fades between views. + * + * @param fadeInView View to fade in when transitioning to AOD. + * @param fadeOutView View to fade out when transitioning to AOD. + */ + CrossFadeDarkController(View fadeInView, View fadeOutView) { + mFadeInView = fadeInView; + mFadeOutView = fadeOutView; + } + + /** + * Sets the amount the system has transitioned to the dark state. + * + * @param darkAmount Amount of transition to dark state: 1f for AOD and 0f for lock screen. + */ + void setDarkAmount(float darkAmount) { + mFadeInView.setAlpha(Math.max(0f, 2f * darkAmount - 1f)); + if (darkAmount == 0f) { + mFadeInView.setVisibility(View.GONE); + } else { + if (mFadeInView.getVisibility() == View.GONE) { + mFadeInView.setVisibility(View.VISIBLE); + } + } + mFadeOutView.setAlpha(Math.max(0f, 1f - 2f * darkAmount)); + if (darkAmount == 1f) { + mFadeOutView.setVisibility(View.GONE); + } else { + if (mFadeOutView.getVisibility() == View.GONE) { + mFadeOutView.setVisibility(View.VISIBLE); + } + } + } +} diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java new file mode 100644 index 000000000000..2c709e0393bd --- /dev/null +++ b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2019 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.clock; + +import android.content.Context; +import android.text.format.DateFormat; +import android.util.AttributeSet; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import com.android.keyguard.R; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.TimeZone; + +/** + * Clock composed of two images that rotate with the time. + * + * The images are the clock hands. ImageClock expects two child ImageViews + * with ids hour_hand and minute_hand. + */ +public class ImageClock extends FrameLayout { + + private ImageView mHourHand; + private ImageView mMinuteHand; + private Calendar mTime; + private String mDescFormat; + private TimeZone mTimeZone; + + public ImageClock(Context context) { + this(context, null); + } + + public ImageClock(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public ImageClock(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mTime = Calendar.getInstance(); + mDescFormat = ((SimpleDateFormat) DateFormat.getTimeFormat(context)).toLocalizedPattern(); + } + + /** + * Call when the time changes to update the rotation of the clock hands. + */ + public void onTimeChanged() { + mTime.setTimeInMillis(System.currentTimeMillis()); + final float hourAngle = mTime.get(Calendar.HOUR) * 30f; + mHourHand.setRotation(hourAngle); + final float minuteAngle = mTime.get(Calendar.MINUTE) * 6f; + mMinuteHand.setRotation(minuteAngle); + setContentDescription(DateFormat.format(mDescFormat, mTime)); + invalidate(); + } + + /** + * Call when the time zone has changed to update clock hands. + * + * @param timeZone The updated time zone that will be used. + */ + public void onTimeZoneChanged(TimeZone timeZone) { + mTimeZone = timeZone; + mTime.setTimeZone(timeZone); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mHourHand = findViewById(R.id.hour_hand); + mMinuteHand = findViewById(R.id.minute_hand); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mTime = Calendar.getInstance(mTimeZone != null ? mTimeZone : TimeZone.getDefault()); + onTimeChanged(); + } +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java new file mode 100644 index 000000000000..9e946faf2a52 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/BubbleClockControllerTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2019 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.clock; + +import static com.google.common.truth.Truth.assertThat; + +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper.RunWithLooper; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +public final class BubbleClockControllerTest extends SysuiTestCase { + + private BubbleClockController mClockController; + + @Before + public void setUp() { + LayoutInflater layoutInflater = LayoutInflater.from(getContext()); + mClockController = BubbleClockController.build(layoutInflater); + } + + @Test + public void setDarkAmount_fadeIn() { + ViewGroup smallClockFrame = (ViewGroup) mClockController.getView(); + View smallClock = smallClockFrame.getChildAt(0); + // WHEN dark amount is set to AOD + mClockController.setDarkAmount(1f); + // THEN small clock should not be shown. + assertThat(smallClock.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void setTextColor_setDigitalClock() { + ViewGroup smallClock = (ViewGroup) mClockController.getView(); + // WHEN text color is set + mClockController.setTextColor(42); + // THEN child of small clock should have text color set. + TextView digitalClock = (TextView) smallClock.getChildAt(0); + assertThat(digitalClock.getCurrentTextColor()).isEqualTo(42); + } +} diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/CrossFadeDarkControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/CrossFadeDarkControllerTest.java new file mode 100644 index 000000000000..fd7657ff18cc --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/CrossFadeDarkControllerTest.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2019 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.clock; + +import static com.google.common.truth.Truth.assertThat; + +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper.RunWithLooper; +import android.view.View; +import android.widget.TextView; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@RunWithLooper +public final class CrossFadeDarkControllerTest extends SysuiTestCase { + + private View mViewFadeIn; + private View mViewFadeOut; + private CrossFadeDarkController mDarkController; + + @Before + public void setUp() { + mViewFadeIn = new TextView(getContext()); + mViewFadeIn.setVisibility(View.VISIBLE); + mViewFadeIn.setAlpha(1f); + mViewFadeOut = new TextView(getContext()); + mViewFadeOut.setVisibility(View.VISIBLE); + mViewFadeOut.setAlpha(1f); + + mDarkController = new CrossFadeDarkController(mViewFadeIn, mViewFadeOut); + } + + @Test + public void setDarkAmount_fadeIn() { + // WHEN dark amount corresponds to AOD + mDarkController.setDarkAmount(1f); + // THEN fade in view should be faded in and fade out view faded out. + assertThat(mViewFadeIn.getAlpha()).isEqualTo(1f); + assertThat(mViewFadeIn.getVisibility()).isEqualTo(View.VISIBLE); + assertThat(mViewFadeOut.getAlpha()).isEqualTo(0f); + assertThat(mViewFadeOut.getVisibility()).isEqualTo(View.GONE); + } + + @Test + public void setDarkAmount_fadeOut() { + // WHEN dark amount corresponds to lock screen + mDarkController.setDarkAmount(0f); + // THEN fade out view should bed faded out and fade in view faded in. + assertThat(mViewFadeIn.getAlpha()).isEqualTo(0f); + assertThat(mViewFadeIn.getVisibility()).isEqualTo(View.GONE); + assertThat(mViewFadeOut.getAlpha()).isEqualTo(1f); + assertThat(mViewFadeOut.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void setDarkAmount_partialFadeIn() { + // WHEN dark amount corresponds to a partial transition + mDarkController.setDarkAmount(0.9f); + // THEN views should have intermediate alpha value. + assertThat(mViewFadeIn.getAlpha()).isGreaterThan(0f); + assertThat(mViewFadeIn.getAlpha()).isLessThan(1f); + assertThat(mViewFadeIn.getVisibility()).isEqualTo(View.VISIBLE); + } + + @Test + public void setDarkAmount_partialFadeOut() { + // WHEN dark amount corresponds to a partial transition + mDarkController.setDarkAmount(0.1f); + // THEN views should have intermediate alpha value. + assertThat(mViewFadeOut.getAlpha()).isGreaterThan(0f); + assertThat(mViewFadeOut.getAlpha()).isLessThan(1f); + assertThat(mViewFadeOut.getVisibility()).isEqualTo(View.VISIBLE); + } +} |