Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b1c41456 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add custom stretch clock face."

parents c2e5d34d 496916b1
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
<?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.StretchAnalogClock
      android:id="@+id/analog_clock"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
  />
</com.android.keyguard.clock.ClockLayout>
+7 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ import android.widget.TextClock;
import androidx.annotation.VisibleForTesting;

import com.android.keyguard.clock.BubbleClockController;
import com.android.keyguard.clock.StretchAnalogClockController;
import com.android.systemui.Dependency;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.statusbar.StatusBarState;
@@ -146,6 +147,12 @@ public class KeyguardClockSwitch extends RelativeLayout {
                                Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
                                BubbleClockController.class.getName(),
                                () -> BubbleClockController.build(mLayoutInflater)))
                .withDefault(
                        new SettingsGattedSupplier(
                                mContentResolver,
                                Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
                                StretchAnalogClockController.class.getName(),
                                () -> StretchAnalogClockController.build(mLayoutInflater)))
                .build();
        mContentResolver.registerContentObserver(
                Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE),
+141 −0
Original line number Diff line number Diff line
/*
 * 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.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

import java.util.Calendar;
import java.util.TimeZone;

/**
 * Analog clock where the minute hand extends off of the screen.
 */
public class StretchAnalogClock extends View {

    private static final int DEFAULT_COLOR = Color.parseColor("#F5C983");
    private static final float HOUR_STROKE_WIDTH = 60f;
    private static final float MINUTE_STROKE_WIDTH = 20f;
    private static final float CENTER_GAP_AND_CIRCLE_RADIUS = 80f;

    private final Paint mHourPaint = new Paint();
    private final Paint mMinutePaint = new Paint();
    private Calendar mTime;
    private TimeZone mTimeZone;

    public StretchAnalogClock(Context context) {
        this(context, null);
    }

    public StretchAnalogClock(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public StretchAnalogClock(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public StretchAnalogClock(Context context, AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    /**
     * Call when the time changes to update the clock hands.
     */
    public void onTimeChanged() {
        mTime.setTimeInMillis(System.currentTimeMillis());
        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) {
        mTime.setTimeZone(timeZone);
    }

    /**
     * Set the color of the minute hand.
     */
    public void setMinuteHandColor(int color) {
        mMinutePaint.setColor(color);
    }

    private void init() {
        mHourPaint.setColor(DEFAULT_COLOR);
        mHourPaint.setStrokeWidth(HOUR_STROKE_WIDTH);
        mHourPaint.setAntiAlias(true);
        mHourPaint.setStrokeCap(Paint.Cap.ROUND);

        mMinutePaint.setColor(Color.WHITE);
        mMinutePaint.setStrokeWidth(MINUTE_STROKE_WIDTH);
        mMinutePaint.setAntiAlias(true);
        mMinutePaint.setStrokeCap(Paint.Cap.ROUND);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        final float centerX = getWidth() / 2f;
        final float centerY = getHeight() / 2f;

        final float minutesRotation = mTime.get(Calendar.MINUTE) * 6f;
        final float hoursRotation = (mTime.get(Calendar.HOUR) * 30);

        // Compute length of clock hands. Hour hand is 60% the length from center to edge
        // and minute hand is twice the length to make sure it extends past screen edge.
        double sMinuteHandLengthFactor = Math.sin(2d * Math.PI * minutesRotation / 360d);
        float sMinuteHandLength = (float) (2d * (centerY + (centerX - centerY)
                * sMinuteHandLengthFactor * sMinuteHandLengthFactor));
        double sHourHandLengthFactor = Math.sin(2d * Math.PI * hoursRotation / 360d);
        float sHourHandLength = (float) (0.6d * (centerY + (centerX - centerY)
                * sHourHandLengthFactor * sHourHandLengthFactor));

        canvas.save();

        canvas.rotate(minutesRotation, centerX, centerY);
        canvas.drawLine(
                centerX,
                centerY + CENTER_GAP_AND_CIRCLE_RADIUS,
                centerX,
                centerY - sMinuteHandLength,
                mMinutePaint);

        canvas.rotate(hoursRotation - minutesRotation, centerX, centerY);
        canvas.drawLine(
                centerX,
                centerY + CENTER_GAP_AND_CIRCLE_RADIUS,
                centerX,
                centerY - sHourHandLength,
                mHourPaint);

        canvas.restore();
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mTime = Calendar.getInstance(mTimeZone != null ? mTimeZone : TimeZone.getDefault());
        onTimeChanged();
    }
}
+115 −0
Original line number Diff line number Diff line
/*
 * 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 Stretch clock that can appear on lock screen and AOD.
 */
public class StretchAnalogClockController implements ClockPlugin {

    /**
     * Custom clock shown on AOD screen and behind stack scroller on lock.
     */
    private View mBigClockView;
    private TextClock mDigitalClock;
    private StretchAnalogClock mAnalogClock;

    /**
     * Small clock shown on lock screen above stack scroller.
     */
    private View mView;
    private TextClock mLockClock;

    /**
     * Controller for transition to dark state.
     */
    private CrossFadeDarkController mDarkController;

    private StretchAnalogClockController() { }

    /**
     * Create a BubbleClockController instance.
     *
     * @param layoutInflater Inflater used to inflate custom clock views.
     */
    public static StretchAnalogClockController build(LayoutInflater layoutInflater) {
        StretchAnalogClockController controller = new StretchAnalogClockController();
        controller.createViews(layoutInflater);
        return controller;
    }

    private void createViews(LayoutInflater layoutInflater) {
        mBigClockView = layoutInflater.inflate(R.layout.stretchanalog_clock, null);
        mAnalogClock = mBigClockView.findViewById(R.id.analog_clock);
        mDigitalClock = mBigClockView.findViewById(R.id.digital_clock);

        mView = layoutInflater.inflate(R.layout.digital_clock, null);
        mLockClock = mView.findViewById(R.id.lock_screen_clock);
        mLockClock.setVisibility(View.GONE);

        mDarkController = new CrossFadeDarkController(mDigitalClock, mLockClock);
    }

    @Override
    public View getView() {
        return mView;
    }

    @Override
    public View getBigClockView() {
        return mBigClockView;
    }

    @Override
    public void setStyle(Style style) {}

    @Override
    public void setTextColor(int color) {
        mLockClock.setTextColor(color);
        mDigitalClock.setTextColor(color);
        mAnalogClock.setMinuteHandColor(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;
    }
}
+66 −0
Original line number Diff line number Diff line
/*
 * 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 StretchAnalogClockControllerTest extends SysuiTestCase {

    private StretchAnalogClockController mClockController;

    @Before
    public void setUp() {
        LayoutInflater layoutInflater = LayoutInflater.from(getContext());
        mClockController = StretchAnalogClockController.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);
    }
}