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

Commit cd42c087 authored by Dave Mankoff's avatar Dave Mankoff
Browse files

Add KeyguardSliceViewController.

This removes view injection from KeyguardSliceView.

It also creates a KeyguardStatusView Dagger Subcomponent should be
initilialized whenever a KeyguardStatusView is inflated. From that
subcomponent, KeyguardClockSwitchController and
KeyguardSliceViewController can both be created and initialized,
passing their related views into their constructor.

This fixes a bug introduced earlier where a
KeyguardClockSwitchController was not being created in one place
where it was needed.

Bug: 162525274
Test: atest SystemUITests
Change-Id: Ie571cb0ca2b793c363e3c8ab397828f0ee939763
parent 71f57443
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.widget.RelativeLayout;
import android.widget.TextClock;

import com.android.internal.colorextraction.ColorExtractor;
import com.android.keyguard.dagger.KeyguardStatusViewScope;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.plugins.ClockPlugin;
@@ -36,6 +37,7 @@ import java.util.TimeZone;
/**
 * Switch to show plugin clock when plugin is connected, otherwise it will show default clock.
 */
@KeyguardStatusViewScope
public class KeyguardClockSwitch extends RelativeLayout {

    private static final String TAG = "KeyguardClockSwitch";
+18 −8
Original line number Diff line number Diff line
@@ -34,10 +34,11 @@ import javax.inject.Inject;
public class KeyguardClockSwitchController {
    private static final boolean CUSTOM_CLOCKS_ENABLED = true;

    private final KeyguardClockSwitch mView;
    private final StatusBarStateController mStatusBarStateController;
    private final SysuiColorExtractor mColorExtractor;
    private final ClockManager mClockManager;
    private KeyguardClockSwitch mView;
    private final KeyguardSliceViewController mKeyguardSliceViewController;

    private final StatusBarStateController.StateListener mStateListener =
            new StatusBarStateController.StateListener() {
@@ -52,10 +53,14 @@ public class KeyguardClockSwitchController {
     *
     * The color palette changes when the wallpaper is changed.
     */
    private final ColorExtractor.OnColorsChangedListener mColorsListener = (extractor, which) -> {
    private final ColorExtractor.OnColorsChangedListener mColorsListener =
            new ColorExtractor.OnColorsChangedListener() {
        @Override
        public void onColorsChanged(ColorExtractor extractor, int which) {
            if ((which & WallpaperManager.FLAG_LOCK) != 0) {
                mView.updateColors(getGradientColors());
            }
        }
    };

    private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
@@ -84,22 +89,27 @@ public class KeyguardClockSwitchController {
    };

    @Inject
    public KeyguardClockSwitchController(StatusBarStateController statusBarStateController,
            SysuiColorExtractor colorExtractor, ClockManager clockManager) {
    public KeyguardClockSwitchController(KeyguardClockSwitch keyguardClockSwitch,
            StatusBarStateController statusBarStateController,
            SysuiColorExtractor colorExtractor, ClockManager clockManager,
            KeyguardSliceViewController keyguardSliceViewController) {
        mView = keyguardClockSwitch;
        mStatusBarStateController = statusBarStateController;
        mColorExtractor = colorExtractor;
        mClockManager = clockManager;
        mKeyguardSliceViewController = keyguardSliceViewController;
    }

    /**
     * Attach the controller to the view it relates to.
     */
    public void attach(KeyguardClockSwitch view) {
        mView = view;
    public void init() {
        if (mView.isAttachedToWindow()) {
            mOnAttachStateChangeListener.onViewAttachedToWindow(mView);
        }
        mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener);

        mKeyguardSliceViewController.init();
    }

    /**
+11 −1
Original line number Diff line number Diff line
@@ -34,12 +34,15 @@ import android.view.View;
import android.view.WindowManager;

import com.android.internal.annotations.VisibleForTesting;
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.navigationbar.NavigationBarController;
import com.android.systemui.navigationbar.NavigationBarView;
import com.android.systemui.util.InjectionInflationController;

import javax.inject.Inject;

public class KeyguardDisplayManager {
    protected static final String TAG = "KeyguardDisplayManager";
    private static boolean DEBUG = KeyguardConstants.DEBUG;
@@ -47,6 +50,7 @@ public class KeyguardDisplayManager {
    private final MediaRouter mMediaRouter;
    private final DisplayManager mDisplayService;
    private final InjectionInflationController mInjectableInflater;
    private final KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
    private final Context mContext;

    private boolean mShowing;
@@ -86,10 +90,13 @@ public class KeyguardDisplayManager {
        }
    };

    @Inject
    public KeyguardDisplayManager(Context context,
            InjectionInflationController injectableInflater) {
            InjectionInflationController injectableInflater,
            KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory) {
        mContext = context;
        mInjectableInflater = injectableInflater;
        mKeyguardStatusViewComponentFactory = keyguardStatusViewComponentFactory;
        mMediaRouter = mContext.getSystemService(MediaRouter.class);
        mDisplayService = mContext.getSystemService(DisplayManager.class);
        mDisplayService.registerDisplayListener(mDisplayListener, null /* handler */);
@@ -138,6 +145,9 @@ public class KeyguardDisplayManager {
                presentation = null;
            }
            if (presentation != null) {
                mKeyguardStatusViewComponentFactory
                        .build(presentation.findViewById(R.id.clock))
                        .getKeyguardClockSwitchController().init();
                mPresentations.append(displayId, presentation);
                return true;
            }
+20 −117
Original line number Diff line number Diff line
@@ -17,11 +17,8 @@
package com.android.keyguard;

import static android.app.slice.Slice.HINT_LIST_ITEM;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.Display.INVALID_DISPLAY;

import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;

import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
@@ -35,28 +32,22 @@ import android.graphics.drawable.Drawable;
import android.graphics.text.LineBreaker;
import android.net.Uri;
import android.os.Trace;
import android.provider.Settings;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.Display;
import android.view.View;
import android.view.animation.Animation;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import androidx.slice.Slice;
import androidx.slice.SliceItem;
import androidx.slice.SliceViewManager;
import androidx.slice.core.SliceQuery;
import androidx.slice.widget.ListContent;
import androidx.slice.widget.RowContent;
import androidx.slice.widget.SliceContent;
import androidx.slice.widget.SliceLiveData;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
@@ -64,11 +55,9 @@ import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.KeyguardSliceProvider;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.wakelock.KeepAwakeAnimationListener;

import java.io.FileDescriptor;
@@ -77,24 +66,17 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.inject.Inject;
import javax.inject.Named;

/**
 * View visible under the clock on the lock screen and AoD.
 */
public class KeyguardSliceView extends LinearLayout implements View.OnClickListener,
        Observer<Slice>, TunerService.Tunable, ConfigurationController.ConfigurationListener {
public class KeyguardSliceView extends LinearLayout implements View.OnClickListener {

    private static final String TAG = "KeyguardSliceView";
    public static final int DEFAULT_ANIM_DURATION = 550;

    private final HashMap<View, PendingIntent> mClickActions;
    private final ActivityStarter mActivityStarter;
    private final ConfigurationController mConfigurationController;
    private ActivityStarter mActivityStarter;
    private final LayoutTransition mLayoutTransition;
    private final TunerService mTunerService;
    private Uri mKeyguardSliceUri;
    @VisibleForTesting
    TextView mTitle;
    private Row mRow;
@@ -109,25 +91,20 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
     * Runnable called whenever the view contents change.
     */
    private Runnable mContentChangeListener;
    private Slice mSlice;
    private boolean mHasHeader;
    private final int mRowWithHeaderPadding;
    private final int mRowPadding;
    private float mRowTextSize;
    private float mRowWithHeaderTextSize;
    private KeyguardSliceViewController mController;

    @Inject
    public KeyguardSliceView(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs,
            ActivityStarter activityStarter, ConfigurationController configurationController,
            TunerService tunerService, @Main Resources resources) {
    public KeyguardSliceView(Context context, AttributeSet attrs) {
        super(context, attrs);

        mTunerService = tunerService;
        Resources resources = context.getResources();
        mClickActions = new HashMap<>();
        mRowPadding = resources.getDimensionPixelSize(R.dimen.subtitle_clock_padding);
        mRowWithHeaderPadding = resources.getDimensionPixelSize(R.dimen.header_subtitle_padding);
        mActivityStarter = activityStarter;
        mConfigurationController = configurationController;

        mLayoutTransition = new LayoutTransition();
        mLayoutTransition.setStagger(LayoutTransition.CHANGE_APPEARING, DEFAULT_ANIM_DURATION / 2);
@@ -157,34 +134,6 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
        mTitle.setBreakStrategy(LineBreaker.BREAK_STRATEGY_BALANCED);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();

        Display display = getDisplay();
        if (display != null) {
            mDisplayId = display.getDisplayId();
        }
        mTunerService.addTunable(this, Settings.Secure.KEYGUARD_SLICE_URI);
        // Make sure we always have the most current slice
        if (mDisplayId == DEFAULT_DISPLAY) {
            mLiveData.observeForever(this);
        }
        mConfigurationController.addCallback(this);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();

        // TODO(b/117344873) Remove below work around after this issue be fixed.
        if (mDisplayId == DEFAULT_DISPLAY) {
            mLiveData.removeObserver(this);
        }
        mTunerService.removeTunable(this);
        mConfigurationController.removeCallback(this);
    }

    @Override
    public void onVisibilityAggregated(boolean isVisible) {
        super.onVisibilityAggregated(isVisible);
@@ -198,9 +147,9 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
        return mHasHeader;
    }

    private void showSlice() {
    void showSlice(Slice slice) {
        Trace.beginSection("KeyguardSliceView#showSlice");
        if (mSlice == null) {
        if (slice == null) {
            mTitle.setVisibility(GONE);
            mRow.setVisibility(GONE);
            mHasHeader = false;
@@ -212,7 +161,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
        }
        mClickActions.clear();

        ListContent lc = new ListContent(getContext(), mSlice);
        ListContent lc = new ListContent(getContext(), slice);
        SliceContent headerContent = lc.getHeader();
        mHasHeader = headerContent != null && !headerContent.getSliceItem().hasHint(HINT_LIST_ITEM);
        List<SliceContent> subItems = new ArrayList<>();
@@ -326,7 +275,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
    @Override
    public void onClick(View v) {
        final PendingIntent action = mClickActions.get(v);
        if (action != null) {
        if (action != null && mActivityStarter != null) {
            mActivityStarter.startPendingIntentDismissingKeyguard(action);
        }
    }
@@ -339,43 +288,6 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
        mContentChangeListener = contentChangeListener;
    }

    /**
     * LiveData observer lifecycle.
     * @param slice the new slice content.
     */
    @Override
    public void onChanged(Slice slice) {
        mSlice = slice;
        showSlice();
    }

    @Override
    public void onTuningChanged(String key, String newValue) {
        setupUri(newValue);
    }

    /**
     * Sets the slice provider Uri.
     */
    public void setupUri(String uriString) {
        if (uriString == null) {
            uriString = KeyguardSliceProvider.KEYGUARD_SLICE_URI;
        }

        boolean wasObserving = false;
        if (mLiveData != null && mLiveData.hasActiveObservers()) {
            wasObserving = true;
            mLiveData.removeObserver(this);
        }

        mKeyguardSliceUri = Uri.parse(uriString);
        mLiveData = SliceLiveData.fromUri(mContext, mKeyguardSliceUri);

        if (wasObserving) {
            mLiveData.observeForever(this);
        }
    }

    @VisibleForTesting
    int getTextColor() {
        return ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount);
@@ -387,8 +299,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
        updateTextColors();
    }

    @Override
    public void onDensityOrFontScaleChanged() {
    void onDensityOrFontScaleChanged() {
        mIconSize = mContext.getResources().getDimensionPixelSize(R.dimen.widget_icon_size);
        mIconSizeWithHeader = (int) mContext.getResources().getDimension(R.dimen.header_icon_size);
        mRowTextSize = mContext.getResources().getDimensionPixelSize(
@@ -398,23 +309,7 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
    }

    public void refresh() {
        Slice slice;
        Trace.beginSection("KeyguardSliceView#refresh");
        // We can optimize performance and avoid binder calls when we know that we're bound
        // to a Slice on the same process.
        if (KeyguardSliceProvider.KEYGUARD_SLICE_URI.equals(mKeyguardSliceUri.toString())) {
            KeyguardSliceProvider instance = KeyguardSliceProvider.getAttachedInstance();
            if (instance != null) {
                slice = instance.onBindSlice(mKeyguardSliceUri);
            } else {
                Log.w(TAG, "Keyguard slice not bound yet?");
                slice = null;
            }
        } else {
            slice = SliceViewManager.getInstance(getContext()).bindSlice(mKeyguardSliceUri);
        }
        onChanged(slice);
        Trace.endSection();
        mController.refresh();
    }

    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -424,10 +319,18 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
        pw.println("  mRow: " + (mRow == null ? "null" : mRow.getVisibility() == VISIBLE));
        pw.println("  mTextColor: " + Integer.toHexString(mTextColor));
        pw.println("  mDarkAmount: " + mDarkAmount);
        pw.println("  mSlice: " + mSlice);
        pw.println("  mHasHeader: " + mHasHeader);
    }

    public void setActivityStarter(ActivityStarter activityStarter) {
        mActivityStarter = activityStarter;
    }

    public void setController(KeyguardSliceViewController keyguardSliceViewController) {
        // TODO: remove this method.
        mController = keyguardSliceViewController;
    }

    public static class Row extends LinearLayout {

        /**
+184 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.Display.DEFAULT_DISPLAY;

import android.net.Uri;
import android.os.Trace;
import android.provider.Settings;
import android.util.Log;
import android.view.Display;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import androidx.slice.Slice;
import androidx.slice.SliceViewManager;
import androidx.slice.widget.SliceLiveData;

import com.android.keyguard.dagger.KeyguardStatusViewScope;
import com.android.systemui.Dumpable;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardSliceProvider;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.tuner.TunerService;

import java.io.FileDescriptor;
import java.io.PrintWriter;

import javax.inject.Inject;

/** Controller for a {@link KeyguardSliceView}. */
@KeyguardStatusViewScope
public class KeyguardSliceViewController implements Dumpable {
    private static final String TAG = "KeyguardSliceViewController";

    private final KeyguardSliceView mView;
    private final ActivityStarter mActivityStarter;
    private final ConfigurationController mConfigurationController;
    private final TunerService mTunerService;
    private final DumpManager mDumpManager;
    private int mDisplayId;
    private LiveData<Slice> mLiveData;
    private Uri mKeyguardSliceUri;
    private Slice mSlice;

    private final View.OnAttachStateChangeListener mOnAttachStateChangeListener =
            new View.OnAttachStateChangeListener() {

                @Override
                public void onViewAttachedToWindow(View v) {

                    Display display = mView.getDisplay();
                    if (display != null) {
                        mDisplayId = display.getDisplayId();
                    }
                    mTunerService.addTunable(mTunable, Settings.Secure.KEYGUARD_SLICE_URI);
                    // Make sure we always have the most current slice
                    if (mDisplayId == DEFAULT_DISPLAY && mLiveData != null) {
                        mLiveData.observeForever(mObserver);
                    }
                    mConfigurationController.addCallback(mConfigurationListener);
                    mDumpManager.registerDumpable(TAG, KeyguardSliceViewController.this);
                }

                @Override
                public void onViewDetachedFromWindow(View v) {

                    // TODO(b/117344873) Remove below work around after this issue be fixed.
                    if (mDisplayId == DEFAULT_DISPLAY) {
                        mLiveData.removeObserver(mObserver);
                    }
                    mTunerService.removeTunable(mTunable);
                    mConfigurationController.removeCallback(mConfigurationListener);
                    mDumpManager.unregisterDumpable(TAG);
                }
            };

    TunerService.Tunable mTunable = (key, newValue) -> setupUri(newValue);

    ConfigurationController.ConfigurationListener mConfigurationListener =
            new ConfigurationController.ConfigurationListener() {
        @Override
        public void onDensityOrFontScaleChanged() {
            mView.onDensityOrFontScaleChanged();
        }
    };

    Observer<Slice> mObserver = new Observer<Slice>() {
        @Override
        public void onChanged(Slice slice) {
            mSlice = slice;
            mView.showSlice(slice);
        }
    };

    @Inject
    public KeyguardSliceViewController(KeyguardSliceView keyguardSliceView,
            ActivityStarter activityStarter, ConfigurationController configurationController,
            TunerService tunerService, DumpManager dumpManager) {
        mView = keyguardSliceView;
        mActivityStarter = activityStarter;
        mConfigurationController = configurationController;
        mTunerService = tunerService;
        mDumpManager = dumpManager;
    }

    /** Initialize the controller. */
    public void init() {
        if (mView.isAttachedToWindow()) {
            mOnAttachStateChangeListener.onViewAttachedToWindow(mView);
        }
        mView.addOnAttachStateChangeListener(mOnAttachStateChangeListener);
        mView.setActivityStarter(mActivityStarter);
        mView.setController(this);  // TODO: remove this.
    }

    /**
     * Sets the slice provider Uri.
     */
    public void setupUri(String uriString) {
        if (uriString == null) {
            uriString = KeyguardSliceProvider.KEYGUARD_SLICE_URI;
        }

        boolean wasObserving = false;
        if (mLiveData != null && mLiveData.hasActiveObservers()) {
            wasObserving = true;
            mLiveData.removeObserver(mObserver);
        }

        mKeyguardSliceUri = Uri.parse(uriString);
        mLiveData = SliceLiveData.fromUri(mView.getContext(), mKeyguardSliceUri);

        if (wasObserving) {
            mLiveData.observeForever(mObserver);
        }
    }

    /**
     * Update contents of the view.
     */
    public void refresh() {
        Slice slice;
        Trace.beginSection("KeyguardSliceViewController#refresh");
        // We can optimize performance and avoid binder calls when we know that we're bound
        // to a Slice on the same process.
        if (KeyguardSliceProvider.KEYGUARD_SLICE_URI.equals(mKeyguardSliceUri.toString())) {
            KeyguardSliceProvider instance = KeyguardSliceProvider.getAttachedInstance();
            if (instance != null) {
                slice = instance.onBindSlice(mKeyguardSliceUri);
            } else {
                Log.w(TAG, "Keyguard slice not bound yet?");
                slice = null;
            }
        } else {
            // TODO: Make SliceViewManager injectable
            slice = SliceViewManager.getInstance(mView.getContext()).bindSlice(mKeyguardSliceUri);
        }
        mObserver.onChanged(slice);
        Trace.endSection();
    }

    @Override
    public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
        pw.println("  mSlice: " + mSlice);
    }
}
Loading