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

Commit 89105ae4 authored by Roman Birg's avatar Roman Birg
Browse files

SystemUI: move keyguard visualizer behind notifications



Also, handle hiding and showing the visualizer when dragging
notifications, or tapping on them.

Change-Id: I9402dded1cd76676887caae5f3aa075b03a6e7ea
Signed-off-by: default avatarRoman Birg <roman@cyngn.com>
parent 44adf3e4
Loading
Loading
Loading
Loading
+0 −10
Original line number Diff line number Diff line
@@ -68,14 +68,4 @@
        android:tint="#ffffffff"
        android:contentDescription="@string/accessibility_unlock_button" />

    <com.pheelicks.visualizer.VisualizerView
        android:id="@+id/visualizerView"
        android:gravity="bottom"
        android:layout_gravity="bottom"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipChildren="false"
        android:clipToPadding="false"
        android:visibility="visible"/>

</com.android.systemui.statusbar.phone.KeyguardBottomAreaView>
+9 −0
Original line number Diff line number Diff line
@@ -39,6 +39,15 @@
                   android:layout_height="match_parent"
                   android:scaleType="centerCrop"
                   android:visibility="invisible" />
        <com.pheelicks.visualizer.VisualizerView
                   android:id="@+id/visualizerView"
                   android:gravity="bottom"
                   android:layout_gravity="bottom"
                   android:layout_width="match_parent"
                   android:layout_height="match_parent"
                   android:clipChildren="false"
                   android:clipToPadding="false"
                   android:visibility="visible"/>
    </com.android.systemui.statusbar.BackDropView>

    <com.android.systemui.statusbar.ScrimView android:id="@+id/scrim_behind"
+1 −1
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@
    <dimen name="kg_visualizer_path_stroke_width">20dp</dimen>

    <!-- Color for the Equalizer tile -->
    <color name="equalizer_fill_color">#32ffffff</color>
    <color name="equalizer_fill_color">#92ffffff</color>

    <!-- The amount of divisions to make for eq bars -->
    <integer name="kg_visualizer_divisions">16</integer>
+270 −4
Original line number Diff line number Diff line
@@ -16,18 +16,57 @@

package com.android.systemui.statusbar;

import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.PowerManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.R;
import com.android.systemui.cm.UserContentObserver;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.pheelicks.visualizer.AudioData;
import com.pheelicks.visualizer.FFTData;
import com.pheelicks.visualizer.VisualizerView;
import com.pheelicks.visualizer.renderer.Renderer;

/**
 * A view who contains media artwork.
 */
public class BackDropView extends FrameLayout
{
public class BackDropView extends FrameLayout {
    final static String TAG = BackDropView.class.getSimpleName();
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    private PhoneStatusBar mPhoneStatusBar;

    // the length to animate the visualizer in and out
    private static final int VISUALIZER_ANIMATION_DURATION_IN = 300;
    private static final int VISUALIZER_ANIMATION_DURATION_OUT = 0;
    private Runnable mOnVisibilityChangedRunnable;

    private VisualizerView mVisualizer;
    private boolean mScreenOn;
    private boolean mLinked;
    private boolean mVisualizerEnabled;
    private boolean mPowerSaveModeEnabled;
    private SettingsObserver mSettingsObserver;

    public BackDropView(Context context) {
        super(context);
    }
@@ -47,7 +86,7 @@ public class BackDropView extends FrameLayout

    @Override
    public boolean hasOverlappingRendering() {
        return false;
        return mLinked;
    }

    @Override
@@ -56,10 +95,237 @@ public class BackDropView extends FrameLayout
        if (changedView == this && mOnVisibilityChangedRunnable != null) {
            mOnVisibilityChangedRunnable.run();
        }
        if (!isShown()) {
            requestVisualizer(false, 0);
        }
    }

    public void setOnVisibilityChangedRunnable(Runnable runnable) {
        mOnVisibilityChangedRunnable = runnable;
    }

    public void setService(PhoneStatusBar service) {
        mPhoneStatusBar = service;
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mContext.registerReceiver(mReceiver, new IntentFilter(
                PowerManager.ACTION_POWER_SAVE_MODE_CHANGING));
        if (mSettingsObserver == null) {
            mSettingsObserver = new SettingsObserver(new Handler());
        }
        mSettingsObserver.observe();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mSettingsObserver.unobserve();
        mContext.unregisterReceiver(mReceiver);
        requestVisualizer(false, 0);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        if (ActivityManager.isHighEndGfx()) {
            mVisualizer = (VisualizerView) findViewById(R.id.visualizerView);
            if (mVisualizer != null) {
                Paint paint = new Paint();
                Resources res = mContext.getResources();
                paint.setStrokeWidth(res.getDimensionPixelSize(
                        R.dimen.kg_visualizer_path_stroke_width));
                paint.setAntiAlias(true);
                paint.setColor(res.getColor(R.color.equalizer_fill_color));
                paint.setPathEffect(new DashPathEffect(new float[]{
                        res.getDimensionPixelSize(R.dimen.kg_visualizer_path_effect_1),
                        res.getDimensionPixelSize(R.dimen.kg_visualizer_path_effect_2)
                }, 0));

                int bars = res.getInteger(R.integer.kg_visualizer_divisions);
                mVisualizer.addRenderer(new LockscreenBarEqRenderer(bars, paint,
                        res.getInteger(R.integer.kg_visualizer_db_fuzz),
                        res.getInteger(R.integer.kg_visualizer_db_fuzz_factor)));
            }
        }
        KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
    }

    public void requestVisualizer(boolean show, int delay) {
        if (mVisualizer == null || !mVisualizerEnabled || mPowerSaveModeEnabled) {
            return;
        }
        removeCallbacks(mStartVisualizer);
        removeCallbacks(mStopVisualizer);
        if (DEBUG) Log.d(TAG, "requestVisualizer(show: " + show + ", delay: " + delay + ")");
        if (show && mScreenOn
                && mPhoneStatusBar.getBarState() == StatusBarState.KEYGUARD
                && !mPhoneStatusBar.isKeyguardFadingAway()
                && !mPhoneStatusBar.isGoingToNotificationShade()
                && mPhoneStatusBar.getCurrentMediaNotificationKey() != null) {
            if (DEBUG) Log.d(TAG, "--> starting visualizer");
            postDelayed(mStartVisualizer, delay);
        } else {
            if (DEBUG) Log.d(TAG, "--> stopping visualizer");
            postDelayed(mStopVisualizer, delay);
        }
    }

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGING.equals(intent.getAction())) {
                mPowerSaveModeEnabled = intent.getBooleanExtra(PowerManager.EXTRA_POWER_SAVE_MODE,
                        false);
                requestVisualizer(true, 0);
            }
        }
    };

    private final Runnable mStartVisualizer = new Runnable() {
        @Override
        public void run() {
            if (DEBUG) Log.w(TAG, "mStartVisualizer");

            mVisualizer.animate()
                    .alpha(1f)
                    .setDuration(VISUALIZER_ANIMATION_DURATION_IN);
            AsyncTask.execute(new Runnable() {
                @Override
                public void run() {
                    if (mVisualizer != null && !mLinked) {
                        mVisualizer.link(0);
                        mLinked = true;
                    }
                }
            });
        }
    };

    private final Runnable mStopVisualizer = new Runnable() {
        @Override
        public void run() {
            if (DEBUG) Log.w(TAG, "mStopVisualizer");

            mVisualizer.animate()
                    .alpha(0f)
                    .setDuration(VISUALIZER_ANIMATION_DURATION_OUT);
            AsyncTask.execute(new Runnable() {
                @Override
                public void run() {
                    if (mVisualizer != null && mLinked) {
                        mVisualizer.unlink();
                        mLinked = false;
                    }
                }
            });
        }
    };

    private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
            new KeyguardUpdateMonitorCallback() {
                @Override
                public void onUserSwitchComplete(int userId) {
                }

                @Override
                public void onScreenTurnedOn() {
                    mScreenOn = true;
                    requestVisualizer(true, 300);
                }

                @Override
                public void onScreenTurnedOff(int why) {
                    mScreenOn = false;
                    requestVisualizer(false, 0);
                }

                @Override
                public void onKeyguardVisibilityChanged(boolean showing) {
                    if (!showing) {
                        requestVisualizer(false, 0);
                    }
                }
            };

    private static class LockscreenBarEqRenderer extends Renderer {
        private int mDivisions;
        private Paint mPaint;
        private int mDbFuzz;
        private int mDbFuzzFactor;

        /**
         * Renders the FFT data as a series of lines, in histogram form
         *
         * @param divisions - must be a power of 2. Controls how many lines to draw
         * @param paint     - Paint to draw lines with
         * @param dbfuzz    - final dB display adjustment
         * @param dbFactor  - dbfuzz is multiplied by dbFactor.
         */
        public LockscreenBarEqRenderer(int divisions, Paint paint, int dbfuzz, int dbFactor) {
            super();
            if (DEBUG) {
                Log.d(TAG, "Lockscreen EQ Renderer; divisions:" + divisions + ", dbfuzz: "
                        + dbfuzz + "dbFactor: " + dbFactor);
            }
            mDivisions = divisions;
            mPaint = paint;
            mDbFuzz = dbfuzz;
            mDbFuzzFactor = dbFactor;
        }

        @Override
        public void onRender(Canvas canvas, AudioData data, Rect rect) {
            // Do nothing, we only display FFT data
        }

        @Override
        public void onRender(Canvas canvas, FFTData data, Rect rect) {
            for (int i = 0; i < data.bytes.length / mDivisions; i++) {
                mFFTPoints[i * 4] = i * 4 * mDivisions;
                mFFTPoints[i * 4 + 2] = i * 4 * mDivisions;
                byte rfk = data.bytes[mDivisions * i];
                byte ifk = data.bytes[mDivisions * i + 1];
                float magnitude = (rfk * rfk + ifk * ifk);
                int dbValue = magnitude > 0 ? (int) (10 * Math.log10(magnitude)) : 0;

                mFFTPoints[i * 4 + 1] = rect.height();
                mFFTPoints[i * 4 + 3] = rect.height() - ((dbValue * mDbFuzzFactor) + mDbFuzz);
            }

            canvas.drawLines(mFFTPoints, mPaint);
        }
    }

    private class SettingsObserver extends UserContentObserver {
        SettingsObserver(Handler handler) {
            super(handler);
        }

        @Override
        protected void observe() {
            super.observe();
            ContentResolver resolver = mContext.getContentResolver();
            resolver.registerContentObserver(Settings.Secure.getUriFor(
                            Settings.Secure.LOCKSCREEN_VISUALIZER_ENABLED),
                    false, this, UserHandle.USER_ALL);
            update();
        }

        @Override
        protected void unobserve() {
            super.unobserve();
            mContext.getContentResolver().unregisterContentObserver(this);
        }

        @Override
        public void update() {
            ContentResolver resolver = mContext.getContentResolver();
            mVisualizerEnabled = Settings.Secure.getIntForUser(resolver,
                    Settings.Secure.LOCKSCREEN_VISUALIZER_ENABLED, 1, UserHandle.USER_CURRENT) != 0;

        }
    }
}
+0 −193
Original line number Diff line number Diff line
@@ -101,10 +101,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
    private static final int DOZE_ANIMATION_STAGGER_DELAY = 48;
    private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250;

    // the length to animate the visualizer in and out
    private static final int VISUALIZER_ANIMATION_DURATION_IN = 300;
    private static final int VISUALIZER_ANIMATION_DURATION_OUT = 0;

    private KeyguardAffordanceView mCameraImageView;
    private KeyguardAffordanceView mPhoneImageView;
    private KeyguardAffordanceView mLockIcon;
@@ -128,13 +124,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
    private final Interpolator mLinearOutSlowInInterpolator;
    private int mLastUnlockIconRes = 0;

    private VisualizerView mVisualizer;
    private boolean mScreenOn;
    private boolean mLinked;
    private boolean mVisualizerEnabled;
    private boolean mPowerSaveModeEnabled;
    private SettingsObserver mSettingsObserver;

    public KeyguardBottomAreaView(Context context) {
        this(context, null);
    }
@@ -153,7 +142,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
        mTrustDrawable = new TrustDrawable(mContext);
        mLinearOutSlowInInterpolator =
                AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
        mSettingsObserver = new SettingsObserver(new Handler());
    }

    private AccessibilityDelegate mAccessibilityDelegate = new AccessibilityDelegate() {
@@ -217,26 +205,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
        mLockIcon.setOnLongClickListener(this);
        mCameraImageView.setOnClickListener(this);
        mPhoneImageView.setOnClickListener(this);
        if (ActivityManager.isHighEndGfx()) {
            mVisualizer = (VisualizerView) findViewById(R.id.visualizerView);
            if (mVisualizer != null) {
                Paint paint = new Paint();
                Resources res = mContext.getResources();
                paint.setStrokeWidth(res.getDimensionPixelSize(
                        R.dimen.kg_visualizer_path_stroke_width));
                paint.setAntiAlias(true);
                paint.setColor(res.getColor(R.color.equalizer_fill_color));
                paint.setPathEffect(new DashPathEffect(new float[] {
                        res.getDimensionPixelSize(R.dimen.kg_visualizer_path_effect_1),
                        res.getDimensionPixelSize(R.dimen.kg_visualizer_path_effect_2)
                }, 0));

                int bars = res.getInteger(R.integer.kg_visualizer_divisions);
                mVisualizer.addRenderer(new LockscreenBarEqRenderer(bars, paint,
                        res.getInteger(R.integer.kg_visualizer_db_fuzz),
                        res.getInteger(R.integer.kg_visualizer_db_fuzz_factor)));
            }
        }

        initAccessibility();
        updateCustomShortcuts();
@@ -508,7 +476,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
            mTrustDrawable.start();
        } else {
            mTrustDrawable.stop();
            requestVisualizer(false, 0);
        }
        if (changedView == this && visibility == VISIBLE) {
            updateLockIcon();
@@ -519,18 +486,12 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mContext.registerReceiver(mReceiver, new IntentFilter(
                PowerManager.ACTION_POWER_SAVE_MODE_CHANGING));
        mSettingsObserver.observe();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mSettingsObserver.unobserve();
        mContext.unregisterReceiver(mReceiver);
        mTrustDrawable.stop();
        requestVisualizer(false, 0);
    }

    private void updateLockIcon() {
@@ -696,17 +657,6 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
        }
    };

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGING.equals(intent.getAction())) {
                mPowerSaveModeEnabled = intent.getBooleanExtra(PowerManager.EXTRA_POWER_SAVE_MODE,
                        false);
                requestVisualizer(true, 0);
            }
        }
    };

    private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
            new KeyguardUpdateMonitorCallback() {
        @Override
@@ -716,16 +666,12 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL

        @Override
        public void onScreenTurnedOn() {
            mScreenOn = true;
            updateLockIcon();
            requestVisualizer(true, 300);
        }

        @Override
        public void onScreenTurnedOff(int why) {
            mScreenOn = false;
            updateLockIcon();
            requestVisualizer(false, 0);
        }

        @Override
@@ -772,143 +718,4 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
            return mIntrinsicHeight;
        }
    }

    public void requestVisualizer(boolean show, int delay) {
        if (mVisualizer == null || !mVisualizerEnabled || mPowerSaveModeEnabled) {
            return;
        }
        removeCallbacks(mStartVisualizer);
        removeCallbacks(mStopVisualizer);
        if (DEBUG) Log.d(TAG, "requestVisualizer(show: " + show + ", delay: " + delay + ")");
        if (show && mScreenOn
                && mPhoneStatusBar.getBarState() == StatusBarState.KEYGUARD
                && !mPhoneStatusBar.isKeyguardFadingAway()
                && !mPhoneStatusBar.isGoingToNotificationShade()
                && mPhoneStatusBar.getCurrentMediaNotificationKey() != null) {
            if (DEBUG) Log.d(TAG, "--> starting visualizer");
            postDelayed(mStartVisualizer, delay);
        } else {
            if (DEBUG) Log.d(TAG, "--> stopping visualizer");
            postDelayed(mStopVisualizer, delay);
        }
    }

    private static class LockscreenBarEqRenderer extends Renderer {
        private int mDivisions;
        private Paint mPaint;
        private int mDbFuzz;
        private int mDbFuzzFactor;

        /**
         * Renders the FFT data as a series of lines, in histogram form
         *
         * @param divisions - must be a power of 2. Controls how many lines to draw
         * @param paint - Paint to draw lines with
         * @param dbfuzz - final dB display adjustment
         * @param dbFactor - dbfuzz is multiplied by dbFactor.
         */
        public LockscreenBarEqRenderer(int divisions, Paint paint, int dbfuzz, int dbFactor) {
            super();
            if (DEBUG) {
                Log.d(TAG, "Lockscreen EQ Renderer; divisions:" + divisions + ", dbfuzz: "
                        + dbfuzz + "dbFactor: " + dbFactor);
            }
            mDivisions = divisions;
            mPaint = paint;
            mDbFuzz = dbfuzz;
            mDbFuzzFactor = dbFactor;
        }

        @Override
        public void onRender(Canvas canvas, AudioData data, Rect rect) {
            // Do nothing, we only display FFT data
        }

        @Override
        public void onRender(Canvas canvas, FFTData data, Rect rect) {
            for (int i = 0; i < data.bytes.length / mDivisions; i++) {
                mFFTPoints[i * 4] = i * 4 * mDivisions;
                mFFTPoints[i * 4 + 2] = i * 4 * mDivisions;
                byte rfk = data.bytes[mDivisions * i];
                byte ifk = data.bytes[mDivisions * i + 1];
                float magnitude = (rfk * rfk + ifk * ifk);
                int dbValue = magnitude > 0 ? (int) (10 * Math.log10(magnitude)) : 0;

                mFFTPoints[i * 4 + 1] = rect.height();
                mFFTPoints[i * 4 + 3] = rect.height() - ((dbValue * mDbFuzzFactor) + mDbFuzz);
            }

            canvas.drawLines(mFFTPoints, mPaint);
        }
    }

    private final Runnable mStartVisualizer = new Runnable() {
        @Override
        public void run() {
            if (DEBUG) Log.w(TAG, "mStartVisualizer");

            mVisualizer.animate()
                    .alpha(1f)
                    .setDuration(VISUALIZER_ANIMATION_DURATION_IN);
            AsyncTask.execute(new Runnable() {
                @Override
                public void run() {
                    if (mVisualizer != null && !mLinked) {
                        mVisualizer.link(0);
                        mLinked = true;
                    }
                }
            });
        }
    };

    private final Runnable mStopVisualizer = new Runnable() {
        @Override
        public void run() {
            if (DEBUG) Log.w(TAG, "mStopVisualizer");

            mVisualizer.animate()
                    .alpha(0f)
                    .setDuration(VISUALIZER_ANIMATION_DURATION_OUT);
            AsyncTask.execute(new Runnable() {
                @Override
                public void run() {
                    if (mVisualizer != null && mLinked) {
                        mVisualizer.unlink();
                        mLinked = false;
                    }
                }
            });
        }
    };

    private class SettingsObserver extends UserContentObserver {
        SettingsObserver(Handler handler) {
            super(handler);
        }

        @Override
        protected void observe() {
            super.observe();
            ContentResolver resolver = mContext.getContentResolver();
            resolver.registerContentObserver(Settings.Secure.getUriFor(
                    Settings.Secure.LOCKSCREEN_VISUALIZER_ENABLED),
                    false, this, UserHandle.USER_ALL);
            update();
        }

        @Override
        protected void unobserve() {
            super.unobserve();
            mContext.getContentResolver().unregisterContentObserver(this);
        }

        @Override
        public void update() {
            ContentResolver resolver = mContext.getContentResolver();
            mVisualizerEnabled = Settings.Secure.getIntForUser(resolver,
                    Settings.Secure.LOCKSCREEN_VISUALIZER_ENABLED, 1, UserHandle.USER_CURRENT) != 0;

        }
    }
}
Loading