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

Commit 6b80bafe authored by Utkarsh Gupta's avatar Utkarsh Gupta Committed by Steve Kondik
Browse files

SystemUI: use new visualizer from Eleven



Change-Id: I4441440868cac71caa32c91a0875f00a630fe596
Signed-off-by: default avatarUtkarsh Gupta <utkarsh.eminem@gmail.com>
Signed-off-by: default avatarRoman Birg <roman@cyngn.com>

SystemUI: fix NPE crash when Visualizer is not initialized

Change-Id: Ic3774011acfae0312f1642d88c7f5bf2abc9f5a7

SystemUI: hide visualizer when keyguard is occluded

Change-Id: Ia943fd829f7a379fee0f657bb08c34b8c6f36caa
Signed-off-by: default avatarRoman Birg <roman@cyngn.com>

SystemUI: Make lockscreen visualizer battery friendly

In case of offloaded playback, the device is allowed to sleep.
However, if the lockscreen visualizer is enabled, the device
hardly enters deep sleep, even if the screen is off. To prevent
this, enable the visualizer only when the lockscreen is shown.

Change-Id: I484270694b734c9b53e61a7c0ad74391b54fe8cd

SystemUI: more consistent visualizer logic

- only call setVisible from screen on and screen off methods
- eagerly unregister self to make sure we don't get added twice as a
  listener
- Add some debugging under the DEBUG flag

Change-Id: Iada13058f87d4c8d8c8b60f6eebf055652ff2c8d
Signed-off-by: default avatarRoman Birg <roman@cyngn.com>

SystemUI: show visualizer in shade-locked view

This brings back the behavior we had in 12.1 - visualizer would still be
visible in the shade locked state.

Also with the following improvements:
    * use less alpha
    * always attach/detach in a background thread (Async task)
    * use the statusbar state instead keyguard view state listener

Change-Id: I6b8a57f9f0bba6ba0591de0cb1f94a0eb904cc1c
Signed-off-by: default avatarRoman Birg <roman@cyngn.com>

Visualizer: Let visualizer fill the entire available screen

* This will allow it to be more dynamic (landscape lock screen for instance)

Change-Id: I2ffd6b0ca8832812faaa4cc0ec4cdd6071fbec8c
parent 8063e59a
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -27,11 +27,11 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
    android-support-v7-appcompat \
    android-support-v14-preference \
    android-support-v17-leanback \
    android-support-v7-palette \
    android-support-v4 \
    framework-protos \
    SystemUI-proto-tags \
    org.cyanogenmod.platform.internal \
    android-support-v7-palette \
    android-support-v4
    org.cyanogenmod.platform.internal

LOCAL_JAVA_LIBRARIES := telephony-common
LOCAL_FULL_LIBS_MANIFEST_FILES := $(LOCAL_PATH)/AndroidManifest_cm.xml
+4 −0
Original line number Diff line number Diff line
@@ -21,6 +21,10 @@

    <uses-permission android:name="cyanogenmod.permission.WRITE_SECURE_SETTINGS" />

    <!-- Visualizer -->
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />

    <application>

        <activity-alias
+23 −14
Original line number Diff line number Diff line
@@ -43,20 +43,29 @@
                   android:visibility="invisible" />
    </com.android.systemui.statusbar.BackDropView>

    <com.android.systemui.statusbar.ScrimView android:id="@+id/scrim_behind"
    <FrameLayout android:id="@+id/scrimview"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
        android:importantForAccessibility="no"
        sysui:ignoreRightInset="true"
        />

                 android:visibility="visible">
        <com.android.systemui.statusbar.ScrimView
                android:id="@+id/scrim_behind"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:importantForAccessibility="no"/>
        <com.android.systemui.statusbar.AlphaOptimizedView
            android:id="@+id/heads_up_scrim"
            android:layout_width="match_parent"
            android:layout_height="@dimen/heads_up_scrim_height"
            android:background="@drawable/heads_up_scrim"
        sysui:ignoreRightInset="true"
            android:importantForAccessibility="no"/>
        <com.android.systemui.statusbar.VisualizerView
                android:id="@+id/visualizerview"
                android:gravity="bottom"
                android:layout_gravity="bottom"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:visibility="visible"/>
    </FrameLayout>

    <include layout="@layout/status_bar"
        android:layout_width="match_parent"
+395 −0
Original line number Diff line number Diff line
/*
* Copyright (C) 2015 The CyanogenMod 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.systemui.statusbar;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.media.audiofx.Visualizer;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.UserHandle;
import android.support.v7.graphics.Palette;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.android.systemui.cm.UserContentObserver;
import cyanogenmod.providers.CMSettings;

public class VisualizerView extends View implements Palette.PaletteAsyncListener {

    private static final String TAG = VisualizerView.class.getSimpleName();
    private static final boolean DEBUG = false;

    private Paint mPaint;
    private Visualizer mVisualizer;
    private ObjectAnimator mVisualizerColorAnimator;

    private ValueAnimator[] mValueAnimators;
    private float[] mFFTPoints;

    private int mStatusBarState;
    private boolean mVisualizerEnabled = false;
    private boolean mVisible = false;
    private boolean mPlaying = false;
    private boolean mPowerSaveMode = false;
    private boolean mDisplaying = false; // the state we're animating to
    private boolean mDozing = false;
    private boolean mOccluded = false;

    private int mColor;
    private Bitmap mCurrentBitmap;

    private SettingsObserver mObserver;

    private Visualizer.OnDataCaptureListener mVisualizerListener =
            new Visualizer.OnDataCaptureListener() {
        byte rfk, ifk;
        int dbValue;
        float magnitude;

        @Override
        public void onWaveFormDataCapture(Visualizer visualizer, byte[] bytes, int samplingRate) {
        }

        @Override
        public void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate) {
            for (int i = 0; i < 32; i++) {
                mValueAnimators[i].cancel();
                rfk = fft[i * 2 + 2];
                ifk = fft[i * 2 + 3];
                magnitude = rfk * rfk + ifk * ifk;
                dbValue = magnitude > 0 ? (int) (10 * Math.log10(magnitude)) : 0;

                mValueAnimators[i].setFloatValues(mFFTPoints[i * 4 + 1],
                        mFFTPoints[3] - (dbValue * 16f));
                mValueAnimators[i].start();
            }
        }
    };

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

            try {
                mVisualizer = new Visualizer(0);
            } catch (Exception e) {
                Log.e(TAG, "error initializing visualizer", e);
                return;
            }

            mVisualizer.setEnabled(false);
            mVisualizer.setCaptureSize(66);
            mVisualizer.setDataCaptureListener(mVisualizerListener,Visualizer.getMaxCaptureRate(),
                    false, true);
            mVisualizer.setEnabled(true);

            if (DEBUG) {
                Log.w(TAG, "--- mLinkVisualizer run()");
            }
        }
    };

    private final Runnable mAsyncUnlinkVisualizer = new Runnable() {
        @Override
        public void run() {
            AsyncTask.execute(mUnlinkVisualizer);
        }
    };

    private final Runnable mUnlinkVisualizer = new Runnable() {
        @Override
        public void run() {
            if (DEBUG) {
                Log.w(TAG, "+++ mUnlinkVisualizer run(), mVisualizer: " + mVisualizer);
            }
            if (mVisualizer != null) {
                mVisualizer.setEnabled(false);
                mVisualizer.release();
                mVisualizer = null;
            }
            if (DEBUG) {
                Log.w(TAG, "--- mUninkVisualizer run()");
            }
        }
    };

    public VisualizerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        mColor = Color.TRANSPARENT;

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(mColor);

        mFFTPoints = new float[128];
        mValueAnimators = new ValueAnimator[32];
        for (int i = 0; i < 32; i++) {
            final int j = i * 4 + 1;
            mValueAnimators[i] = new ValueAnimator();
            mValueAnimators[i].setDuration(128);
            mValueAnimators[i].addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    mFFTPoints[j] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
        }
    }

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

    public VisualizerView(Context context) {
        this(context, null, 0);
    }

    private void updateViewVisibility() {
        final int curVis = getVisibility();
        final int newVis = mStatusBarState != StatusBarState.SHADE
                && mVisualizerEnabled ? View.VISIBLE : View.GONE;
        if (curVis != newVis) {
            setVisibility(newVis);
            checkStateChanged();
        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mObserver = new SettingsObserver(new Handler());
        mObserver.observe();
        mObserver.update();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mObserver.unobserve();
        mObserver = null;
        mCurrentBitmap = null;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        float barUnit = w / 32f;
        float barWidth = barUnit * 8f / 9f;
        barUnit = barWidth + (barUnit - barWidth) * 32f / 31f;
        mPaint.setStrokeWidth(barWidth);

        for (int i = 0; i < 32; i++) {
            mFFTPoints[i * 4] = mFFTPoints[i * 4 + 2] = i * barUnit + (barWidth / 2);
            mFFTPoints[i * 4 + 1] = h;
            mFFTPoints[i * 4 + 3] = h;
        }
    }

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

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (mVisualizer != null) {
            canvas.drawLines(mFFTPoints, mPaint);
        }
    }

    public void setVisible(boolean visible) {
        if (mVisible != visible) {
            if (DEBUG) {
                Log.i(TAG, "setVisible() called with visible = [" + visible + "]");
            }
            mVisible = visible;
            checkStateChanged();
        }
    }

    public void setDozing(boolean dozing) {
        if (mDozing != dozing) {
            if (DEBUG) {
                Log.i(TAG, "setDozing() called with dozing = [" + dozing + "]");
            }
            mDozing = dozing;
            checkStateChanged();
        }
    }

    public void setPlaying(boolean playing) {
        if (mPlaying != playing) {
            if (DEBUG) {
                Log.i(TAG, "setPlaying() called with playing = [" + playing + "]");
            }
            mPlaying = playing;
            checkStateChanged();
        }
    }

    public void setPowerSaveMode(boolean powerSaveMode) {
        if (mPowerSaveMode != powerSaveMode) {
            if (DEBUG) {
                Log.i(TAG, "setPowerSaveMode() called with powerSaveMode = [" + powerSaveMode + "]");
            }
            mPowerSaveMode = powerSaveMode;
            checkStateChanged();
        }
    }

    public void setOccluded(boolean occluded) {
        if (mOccluded != occluded) {
            if (DEBUG) {
                Log.i(TAG, "setOccluded() called with occluded = [" + occluded + "]");
            }
            mOccluded = occluded;
            checkStateChanged();
        }
    }

    public void setStatusBarState(int statusBarState) {
        if (mStatusBarState != statusBarState) {
            mStatusBarState = statusBarState;
            updateViewVisibility();
        }
    }

    public void setBitmap(Bitmap bitmap) {
        if (mCurrentBitmap == bitmap) {
            return;
        }
        mCurrentBitmap = bitmap;
        if (bitmap != null) {
            Palette.generateAsync(bitmap, this);
        } else {
            setColor(Color.TRANSPARENT);
        }
    }

    @Override
    public void onGenerated(Palette palette) {
        int color = Color.TRANSPARENT;

        color = palette.getVibrantColor(color);
        if (color == Color.TRANSPARENT) {
            color = palette.getLightVibrantColor(color);
            if (color == Color.TRANSPARENT) {
                color = palette.getDarkVibrantColor(color);
            }
        }

        setColor(color);
    }

    private void setColor(int color) {
        if (color == Color.TRANSPARENT) {
            color = Color.WHITE;
        }

        color = Color.argb(140, Color.red(color), Color.green(color), Color.blue(color));

        if (mColor != color) {
            mColor = color;

            if (mVisualizer != null) {
                if (mVisualizerColorAnimator != null) {
                    mVisualizerColorAnimator.cancel();
                }

                mVisualizerColorAnimator = ObjectAnimator.ofArgb(mPaint, "color",
                        mPaint.getColor(), mColor);
                mVisualizerColorAnimator.setStartDelay(600);
                mVisualizerColorAnimator.setDuration(1200);
                mVisualizerColorAnimator.start();
            } else {
                mPaint.setColor(mColor);
            }
        }
    }

    private void checkStateChanged() {
        if (getVisibility() == View.VISIBLE && mVisible && mPlaying && !mDozing && !mPowerSaveMode
                && mVisualizerEnabled && !mOccluded) {
            if (!mDisplaying) {
                mDisplaying = true;
                AsyncTask.execute(mLinkVisualizer);
                animate()
                        .alpha(1f)
                        .withEndAction(null)
                        .setDuration(800);
            }
        } else {
            if (mDisplaying) {
                mDisplaying = false;
                if (mVisible) {
                    animate()
                            .alpha(0f)
                            .withEndAction(mAsyncUnlinkVisualizer)
                            .setDuration(600);
                } else {
                    animate().
                            alpha(0f)
                            .withEndAction(mAsyncUnlinkVisualizer)
                            .setDuration(0);
                }
            }
        }
    }

    private class SettingsObserver extends UserContentObserver {

        public SettingsObserver(Handler handler) {
            super(handler);
        }

        @Override
        protected void update() {
            mVisualizerEnabled = CMSettings.Secure.getInt(getContext().getContentResolver(),
                    CMSettings.Secure.LOCKSCREEN_VISUALIZER_ENABLED, 1) != 0;
            checkStateChanged();
            updateViewVisibility();
        }

        @Override
        protected void observe() {
            super.observe();
            getContext().getContentResolver().registerContentObserver(
                    CMSettings.Secure.getUriFor(CMSettings.Secure.LOCKSCREEN_VISUALIZER_ENABLED),
                    false, this, UserHandle.USER_CURRENT);
        }

        @Override
        protected void unobserve() {
            super.unobserve();
            getContext().getContentResolver().unregisterContentObserver(this);
        }
    }
}
+39 −2
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@ import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
@@ -156,6 +157,7 @@ import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.SignalClusterView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.VisualizerView;
import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -617,6 +619,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    private PorterDuffXfermode mSrcXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
    private PorterDuffXfermode mSrcOverXferMode = new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER);

    private VisualizerView mVisualizerView;
    private boolean mScreenOn;
    private boolean mKeyguardShowingMedia;

    private MediaSessionManager mMediaSessionManager;
    private MediaController mMediaController;
    private String mMediaNotificationKey;
@@ -632,6 +638,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
                    clearCurrentMediaNotification();
                    updateMediaMetaData(true, true);
                }
                mVisualizerView.setPlaying(state.getState() == PlaybackState.STATE_PLAYING);
            }
        }

@@ -941,8 +948,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
        mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front);
        mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back);

        ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
        ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
        FrameLayout scrimView = (FrameLayout) mStatusBarWindow.findViewById(R.id.scrimview);
        ScrimView scrimBehind = (ScrimView) scrimView.findViewById(R.id.scrim_behind);
        ScrimView scrimInFront =
                (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);

        View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
        mScrimController = SystemUIFactory.getInstance().createScrimController(
                scrimBehind, scrimInFront, headsUpScrim);
@@ -962,6 +972,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
        mStackScroller.setScrimController(mScrimController);
        mStatusBarView.setScrimController(mScrimController);
        mDozeScrimController = new DozeScrimController(mScrimController, context);
        mVisualizerView = (VisualizerView) scrimView.findViewById(R.id.visualizerview);

        mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
        mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
@@ -2285,6 +2296,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
                artworkDrawable = new BitmapDrawable(mBackdropBack.getResources(), artworkBitmap);
            }
        }
        mKeyguardShowingMedia = artworkDrawable != null;

        boolean allowWhenShade = false;
        if (ENABLE_LOCKSCREEN_WALLPAPER && artworkDrawable == null) {
            Bitmap lockWallpaper = mLockscreenWallpaper.getBitmap();
@@ -2301,8 +2314,23 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
        boolean hideBecauseOccluded = mStatusBarKeyguardViewManager != null
                && mStatusBarKeyguardViewManager.isOccluded();

        final boolean keyguardVisible = (mState != StatusBarState.SHADE);
        final boolean hasArtwork = artworkDrawable != null;

        if (!mKeyguardFadingAway && keyguardVisible && hasArtwork && mScreenOn) {
            // if there's album art, ensure visualizer is visible
            mVisualizerView.setPlaying(mMediaController != null
                    && mMediaController.getPlaybackState() != null
                    && mMediaController.getPlaybackState().getState()
                            == PlaybackState.STATE_PLAYING);
        }

        if (keyguardVisible && mKeyguardShowingMedia &&
                (artworkDrawable instanceof BitmapDrawable)) {
            // always use current backdrop to color eq
            mVisualizerView.setBitmap(((BitmapDrawable)artworkDrawable).getBitmap());
        }

        if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK)
                && (mState != StatusBarState.SHADE || allowWhenShade)
                && mFingerprintUnlockController.getMode()
@@ -3679,12 +3707,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
                }
            }
            else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                mScreenOn = false;
                notifyNavigationBarScreenOn(false);
                notifyHeadsUpScreenOff();
                finishBarAnimations();
                resetUserExpandedStates();
            }
            else if (Intent.ACTION_SCREEN_ON.equals(action)) {
                mScreenOn = true;
                notifyNavigationBarScreenOn(true);
            } else if (cyanogenmod.content.Intent.ACTION_SCREEN_CAMERA_GESTURE.equals(action)) {
                boolean userSetupComplete = Settings.Secure.getInt(mContext.getContentResolver(),
@@ -4479,6 +4509,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
        mDozeScrimController.setDozing(mDozing &&
                mFingerprintUnlockController.getMode()
                        != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING, animate);
        mVisualizerView.setDozing(mDozing);
    }

    public void updateStackScrollerState(boolean goingToFullShade, boolean fromShadeLocked) {
@@ -4595,6 +4626,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
            removeRemoteInputEntriesKeptUntilCollapsed();
        }
        mState = state;
        mVisualizerView.setStatusBarState(state);
        mGroupManager.setStatusBarState(state);
        mFalsingManager.setStatusBarState(state);
        mStatusBarWindowManager.setStatusBarState(state);
@@ -4930,6 +4962,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
    public void onScreenTurnedOn() {
        mScreenTurningOn = false;
        mDozeScrimController.onScreenTurnedOn();
        mVisualizerView.setVisible(true);
    }

    /**
@@ -5081,6 +5114,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
        updateDozingState();
    }

    public VisualizerView getVisualizer() {
        return mVisualizerView;
    }

    private final class ShadeUpdates {
        private final ArraySet<String> mVisibleNotifications = new ArraySet<String>();
        private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>();
Loading