Add clock plugin function

Use clock plugin interface to replace current TextClock in keyguard

Bug: 111971817
Test: atest SystemUITests
Change-Id: Ib6920844700445d9cd3ffa4159cd7f630eaa853b
This commit is contained in:
Kunhung Li
2018-07-30 19:30:25 +08:00
parent 1b35253f58
commit 29007e6d69
7 changed files with 374 additions and 32 deletions

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
**
** Copyright 2018, 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.
*/
-->
<!-- This is a view that shows clock information in Keyguard. -->
<com.android.keyguard.KeyguardClockSwitch
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/default_clock_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:letterSpacing="0.03"
android:textColor="?attr/wallpaperTextColor"
android:singleLine="true"
style="@style/widget_big_thin"
android:format12Hour="@string/keyguard_widget_12_hours_format"
android:format24Hour="@string/keyguard_widget_24_hours_format" />
</com.android.keyguard.KeyguardClockSwitch>

View File

@@ -38,19 +38,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|top">
<TextClock
android:id="@+id/clock_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true"
android:letterSpacing="0.03"
android:textColor="?attr/wallpaperTextColor"
android:singleLine="true"
style="@style/widget_big_thin"
android:format12Hour="@string/keyguard_widget_12_hours_format"
android:format24Hour="@string/keyguard_widget_24_hours_format" />
<include layout="@layout/keyguard_clock_switch"
android:id="@+id/clock_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View
android:id="@+id/clock_separator"
android:layout_width="@dimen/widget_separator_width"

View File

@@ -55,19 +55,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|top">
<TextClock
android:id="@+id/clock_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_centerHorizontal="true"
android:layout_alignParentTop="true"
android:letterSpacing="0.03"
android:textColor="?attr/wallpaperTextColor"
android:singleLine="true"
style="@style/widget_big_thin"
android:format12Hour="@string/keyguard_widget_12_hours_format"
android:format24Hour="@string/keyguard_widget_24_hours_format" />
<include layout="@layout/keyguard_clock_switch"
android:id="@+id/clock_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View
android:id="@+id/clock_separator"
android:layout_width="@dimen/widget_separator_width"

View File

@@ -0,0 +1,155 @@
package com.android.keyguard;
import android.content.Context;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextClock;
import androidx.annotation.VisibleForTesting;
import com.android.systemui.Dependency;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
/**
* Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
*/
public class KeyguardClockSwitch extends FrameLayout {
/**
* Optional/alternative clock injected via plugin.
*/
private ClockPlugin mClockPlugin;
/**
* Default clock.
*/
private TextClock mClockView;
private final PluginListener<ClockPlugin> mClockPluginListener =
new PluginListener<ClockPlugin>() {
@Override
public void onPluginConnected(ClockPlugin plugin, Context pluginContext) {
View view = plugin.getView();
if (view != null) {
mClockPlugin = plugin;
addView(view, -1,
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
initPluginParams();
mClockView.setVisibility(View.GONE);
}
}
@Override
public void onPluginDisconnected(ClockPlugin plugin) {
View view = plugin.getView();
if (view != null) {
mClockPlugin = null;
removeView(view);
mClockView.setVisibility(View.VISIBLE);
}
}
};
public KeyguardClockSwitch(Context context) {
this(context, null);
}
public KeyguardClockSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mClockView = findViewById(R.id.default_clock_view);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
Dependency.get(PluginManager.class).addPluginListener(mClockPluginListener,
ClockPlugin.class);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Dependency.get(PluginManager.class).removePluginListener(mClockPluginListener);
}
/**
* It will also update plugin setStyle if plugin is connected.
*/
public void setStyle(Style style) {
mClockView.getPaint().setStyle(style);
if (mClockPlugin != null) {
mClockPlugin.setStyle(style);
}
}
/**
* It will also update plugin setTextColor if plugin is connected.
*/
public void setTextColor(int color) {
mClockView.setTextColor(color);
if (mClockPlugin != null) {
mClockPlugin.setTextColor(color);
}
}
public void setShowCurrentUserTime(boolean showCurrentUserTime) {
mClockView.setShowCurrentUserTime(showCurrentUserTime);
}
public void setElegantTextHeight(boolean elegant) {
mClockView.setElegantTextHeight(elegant);
}
public void setTextSize(int unit, float size) {
mClockView.setTextSize(unit, size);
}
public void setFormat12Hour(CharSequence format) {
mClockView.setFormat12Hour(format);
}
public void setFormat24Hour(CharSequence format) {
mClockView.setFormat24Hour(format);
}
public Paint getPaint() {
return mClockView.getPaint();
}
public int getCurrentTextColor() {
return mClockView.getCurrentTextColor();
}
public float getTextSize() {
return mClockView.getTextSize();
}
public void refresh() {
mClockView.refresh();
}
/**
* When plugin changes, set all kept parameters into newer plugin.
*/
private void initPluginParams() {
if (mClockPlugin != null) {
mClockPlugin.setStyle(getPaint().getStyle());
mClockPlugin.setTextColor(getCurrentTextColor());
}
}
@VisibleForTesting (otherwise = VisibleForTesting.NONE)
PluginListener getClockPluginListener() {
return mClockPluginListener;
}
}

View File

@@ -39,7 +39,6 @@ import android.util.TypedValue;
import android.view.View;
import android.widget.GridLayout;
import android.widget.RelativeLayout;
import android.widget.TextClock;
import android.widget.TextView;
import com.android.internal.widget.LockPatternUtils;
@@ -64,7 +63,7 @@ public class KeyguardStatusView extends GridLayout implements
private final float mSmallClockScale;
private TextView mLogoutView;
private TextClock mClockView;
private KeyguardClockSwitch mClockView;
private View mClockSeparator;
private TextView mOwnerInfo;
private KeyguardSliceView mKeyguardSlice;
@@ -248,7 +247,7 @@ public class KeyguardStatusView extends GridLayout implements
.scaleX(clockScale)
.scaleY(clockScale)
.withEndAction(() -> {
mClockView.getPaint().setStyle(style);
mClockView.setStyle(style);
mClockView.invalidate();
})
.start();
@@ -256,7 +255,7 @@ public class KeyguardStatusView extends GridLayout implements
mClockView.setY(top);
mClockView.setScaleX(clockScale);
mClockView.setScaleY(clockScale);
mClockView.getPaint().setStyle(style);
mClockView.setStyle(style);
mClockView.invalidate();
}
} else if (view == mClockSeparator) {

View File

@@ -0,0 +1,169 @@
/*
* Copyright (C) 2018 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 static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import android.graphics.Color;
import android.graphics.Paint.Style;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.text.TextPaint;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.TextClock;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidTestingRunner.class)
public class KeyguardClockSwitchTest extends SysuiTestCase {
private PluginManager mPluginManager;
@Mock
TextClock mClockView;
@InjectMocks
KeyguardClockSwitch mKeyguardClockSwitch;
@Before
public void setUp() {
mPluginManager = mDependency.injectMockDependency(PluginManager.class);
LayoutInflater layoutInflater = LayoutInflater.from(getContext());
mKeyguardClockSwitch =
(KeyguardClockSwitch) layoutInflater.inflate(R.layout.keyguard_clock_switch, null);
MockitoAnnotations.initMocks(this);
}
@Test
public void onAttachToWindow_addPluginListener() {
mKeyguardClockSwitch.onAttachedToWindow();
ArgumentCaptor<PluginListener> listener = ArgumentCaptor.forClass(PluginListener.class);
verify(mPluginManager).addPluginListener(listener.capture(), eq(ClockPlugin.class));
}
@Test
public void onDetachToWindow_removePluginListener() {
mKeyguardClockSwitch.onDetachedFromWindow();
ArgumentCaptor<PluginListener> listener = ArgumentCaptor.forClass(PluginListener.class);
verify(mPluginManager).removePluginListener(listener.capture());
}
@Test
public void onPluginConnected_showPluginClock() {
ClockPlugin plugin = mock(ClockPlugin.class);
TextClock pluginView = new TextClock(getContext());
when(plugin.getView()).thenReturn(pluginView);
TextPaint paint = mock(TextPaint.class);
doReturn(paint).when(mClockView).getPaint();
PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
listener.onPluginConnected(plugin, null);
verify(mClockView).setVisibility(GONE);
assertThat(plugin.getView().getParent()).isEqualTo(mKeyguardClockSwitch);
}
@Test
public void onPluginDisconnected_showDefaultClock() {
ClockPlugin plugin = mock(ClockPlugin.class);
TextClock pluginView = new TextClock(getContext());
when(plugin.getView()).thenReturn(pluginView);
mClockView.setVisibility(GONE);
mKeyguardClockSwitch.addView(plugin.getView(), -1,
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
listener.onPluginDisconnected(plugin);
verify(mClockView).setVisibility(VISIBLE);
assertThat(plugin.getView().getParent()).isNull();
}
@Test
public void setTextColor_defaultClockSetTextColor() {
mKeyguardClockSwitch.setTextColor(Color.YELLOW);
verify(mClockView).setTextColor(Color.YELLOW);
}
@Test
public void setTextColor_pluginClockSetTextColor() {
ClockPlugin plugin = mock(ClockPlugin.class);
TextClock pluginView = new TextClock(getContext());
when(plugin.getView()).thenReturn(pluginView);
TextPaint paint = mock(TextPaint.class);
doReturn(paint).when(mClockView).getPaint();
PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
listener.onPluginConnected(plugin, null);
mKeyguardClockSwitch.setTextColor(Color.WHITE);
verify(plugin).setTextColor(Color.WHITE);
}
@Test
public void setStyle_defaultClockSetStyle() {
TextPaint paint = mock(TextPaint.class);
Style style = mock(Style.class);
doReturn(paint).when(mClockView).getPaint();
mKeyguardClockSwitch.setStyle(style);
verify(paint).setStyle(style);
}
@Test
public void setStyle_pluginClockSetStyle() {
ClockPlugin plugin = mock(ClockPlugin.class);
TextClock pluginView = new TextClock(getContext());
when(plugin.getView()).thenReturn(pluginView);
TextPaint paint = mock(TextPaint.class);
doReturn(paint).when(mClockView).getPaint();
Style style = mock(Style.class);
PluginListener listener = mKeyguardClockSwitch.getClockPluginListener();
listener.onPluginConnected(plugin, null);
mKeyguardClockSwitch.setStyle(style);
verify(plugin).setStyle(style);
}
}

View File

@@ -22,7 +22,6 @@ import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper.RunWithLooper;
import android.view.LayoutInflater;
import android.widget.TextClock;
import com.android.systemui.SysuiTestCase;
@@ -40,7 +39,7 @@ public class KeyguardStatusViewTest extends SysuiTestCase {
@Mock
KeyguardSliceView mKeyguardSlice;
@Mock
TextClock mClockView;
KeyguardClockSwitch mClockView;
@InjectMocks
KeyguardStatusView mKeyguardStatusView;