Add custom bubble clock face.
Bug: 122301289 Test: Using adb to set the settings value switches to bubble clock. Change-Id: I9b5ab62796204cfdce7b9beb147f34f80b0db167
This commit is contained in:
@@ -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>
|
||||
@@ -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>
|
||||
52
packages/SystemUI/res-keyguard/layout/bubble_clock.xml
Normal file
52
packages/SystemUI/res-keyguard/layout/bubble_clock.xml
Normal file
@@ -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>
|
||||
35
packages/SystemUI/res-keyguard/layout/digital_clock.xml
Normal file
35
packages/SystemUI/res-keyguard/layout/digital_clock.xml
Normal file
@@ -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>
|
||||
|
||||
22
packages/SystemUI/res-keyguard/values/colors.xml
Normal file
22
packages/SystemUI/res-keyguard/values/colors.xml
Normal file
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user