Android Open Source - Muzei Muzei Blur Renderer






From Project

Back to project page Muzei.

License

The source code is released under:

Apache License

If you think the Android project Muzei listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 * Copyright 2014 Google Inc./*from  w  ww . j a v  a  2s .  c o m*/
 *
 * 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.google.android.apps.muzei.render;

import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.os.Build;
import android.preference.PreferenceManager;
import android.util.DisplayMetrics;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;

import com.google.android.apps.muzei.ArtDetailViewport;
import com.google.android.apps.muzei.event.ArtworkSizeChangedEvent;
import com.google.android.apps.muzei.event.SwitchingPhotosStateChangedEvent;
import com.google.android.apps.muzei.settings.Prefs;
import com.google.android.apps.muzei.util.ImageBlurrer;
import com.google.android.apps.muzei.util.LogUtil;
import com.google.android.apps.muzei.util.MathUtil;
import com.google.android.apps.muzei.util.TickingFloatAnimator;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import de.greenrobot.event.EventBus;

import static com.google.android.apps.muzei.util.LogUtil.LOGE;

public class MuzeiBlurRenderer implements GLSurfaceView.Renderer {
    private static final String TAG = LogUtil.makeLogTag(MuzeiBlurRenderer.class);

    private static final int CROSSFADE_ANIMATION_DURATION = 750;
    private static final int BLUR_ANIMATION_DURATION = 750;

    public static final int DEFAULT_BLUR = 250; // max 500
    public static final int DEFAULT_GREY = 0; // max 500
    public static final int DEMO_DIM = 64;
    public static final int DEMO_GREY = 0;
    public static final int DEFAULT_MAX_DIM = 128; // technical max 255
    public static final float DIM_RANGE = 0.5f; // percent of max dim

    private boolean mDemoMode;
    private boolean mPreview;
    private int mMaxPrescaledBlurPixels;
    private int mBlurKeyframes = 3;
    private int mBlurredSampleSize;
    private int mMaxDim;
    private int mMaxGrey;

    // Model and view matrices. Projection and MVP stored in picture set
    private final float[] mMMatrix = new float[16];
    private final float[] mVMatrix = new float[16];

    private Callbacks mCallbacks;

    private float mAspectRatio;
    private int mHeight;

    private GLPictureSet mCurrentGLPictureSet;
    private GLPictureSet mNextGLPictureSet;
    private GLColorOverlay mColorOverlay;

    private BitmapRegionLoader mQueuedNextBitmapRegionLoader;

    private boolean mSurfaceCreated;

    private volatile float mNormalOffsetX;
    private volatile RectF mCurrentViewport = new RectF(); // [-1, -1] to [1, 1], flipped

    private Context mContext;

    private boolean mIsBlurred = true;
    private boolean mBlurRelatedToArtDetailMode = false;
    private Interpolator mBlurInterpolator = new AccelerateDecelerateInterpolator();
    private TickingFloatAnimator mBlurAnimator;
    private TickingFloatAnimator mCrossfadeAnimator = TickingFloatAnimator.create().from(0);

    public MuzeiBlurRenderer(Context context, Callbacks callbacks) {
        mContext = context;
        mCallbacks = callbacks;

        mBlurKeyframes = getNumberOfKeyframes();
        mBlurAnimator = TickingFloatAnimator.create().from(mBlurKeyframes);

        mCurrentGLPictureSet = new GLPictureSet(0);
        mNextGLPictureSet = new GLPictureSet(1); // for transitioning to next pictures
        setNormalOffsetX(0);
        recomputeMaxPrescaledBlurPixels();
        recomputeMaxDimAmount();
        recomputeGreyAmount();
    }

    @TargetApi(Build.VERSION_CODES.KITKAT)
    private int getNumberOfKeyframes() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            ActivityManager activityManager = (ActivityManager)
                    mContext.getSystemService(Context.ACTIVITY_SERVICE);
            if (activityManager.isLowRamDevice()) {
                return 1;
            }
        }

        return 5;
    }

    public void recomputeMaxPrescaledBlurPixels() {
        // Compute blur sizes
        float maxBlurRadiusOverScreenHeight = PreferenceManager
                .getDefaultSharedPreferences(mContext).getInt(Prefs.PREF_BLUR_AMOUNT, DEFAULT_BLUR)
                * 0.0001f;
        DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
        int maxBlurPx = (int) (dm.heightPixels * maxBlurRadiusOverScreenHeight);
        mBlurredSampleSize = 4;
        while (maxBlurPx / mBlurredSampleSize > ImageBlurrer.MAX_SUPPORTED_BLUR_PIXELS) {
            mBlurredSampleSize <<= 1;
        }
        mMaxPrescaledBlurPixels = maxBlurPx / mBlurredSampleSize;
    }

    public void recomputeMaxDimAmount() {
        mMaxDim = PreferenceManager
                .getDefaultSharedPreferences(mContext).getInt(
                        Prefs.PREF_DIM_AMOUNT, DEFAULT_MAX_DIM);
    }

    public void recomputeGreyAmount() {
        mMaxGrey = mDemoMode
                ? DEMO_GREY
                : PreferenceManager.getDefaultSharedPreferences(mContext)
                .getInt(Prefs.PREF_GREY_AMOUNT, DEFAULT_GREY);
    }

    public void onSurfaceCreated(GL10 unused, EGLConfig config) {
        mSurfaceCreated = false;
        GLES20.glEnable(GLES20.GL_BLEND);
//        GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
        GLES20.glBlendFuncSeparate(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA,
                GLES20.GL_ONE, GLES20.GL_ONE);
        GLES20.glClearColor(0, 0, 0, 0);

        // Set the camera position (View matrix)
        Matrix.setLookAtM(mVMatrix, 0,
                0, 0, 1,
                0, 0, -1,
                0, 1, 0);

        GLColorOverlay.initGl();
        GLPicture.initGl();

        mColorOverlay = new GLColorOverlay(0);

        mSurfaceCreated = true;
        if (mQueuedNextBitmapRegionLoader != null) {
            BitmapRegionLoader loader = mQueuedNextBitmapRegionLoader;
            mQueuedNextBitmapRegionLoader = null;
            setAndConsumeBitmapRegionLoader(loader);
        }
    }

    public void onSurfaceChanged(GL10 unused, int width, int height) {
        GLES20.glViewport(0, 0, width, height);
        hintViewportSize(width, height);
        if (!mDemoMode && !mPreview) {
            // Reset art detail viewports
            ArtDetailViewport.getInstance().setViewport(0, 0, 0, 0, 0, false);
            ArtDetailViewport.getInstance().setViewport(1, 0, 0, 0, 0, false);
        }
        mCurrentGLPictureSet.recomputeTransformMatrices();
        mNextGLPictureSet.recomputeTransformMatrices();
        recomputeMaxPrescaledBlurPixels();
    }

    public void hintViewportSize(int width, int height) {
        mHeight = height;
        mAspectRatio = width * 1f / height;
    }

    public void onDrawFrame(GL10 unused) {
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

        Matrix.setIdentityM(mMMatrix, 0);

        boolean stillAnimating = mCrossfadeAnimator.tick();
        stillAnimating |= mBlurAnimator.tick();

        if (mBlurRelatedToArtDetailMode) {
            mCurrentGLPictureSet.recomputeTransformMatrices();
            mNextGLPictureSet.recomputeTransformMatrices();
        }

        float dimAmount = mCurrentGLPictureSet.mDimAmount;
        mCurrentGLPictureSet.drawFrame(1);
        if (mCrossfadeAnimator.isRunning()) {
            dimAmount = MathUtil.interpolate(dimAmount, mNextGLPictureSet.mDimAmount,
                    mCrossfadeAnimator.currentValue());
            mNextGLPictureSet.drawFrame(mCrossfadeAnimator.currentValue());
        }

        mColorOverlay.setColor(Color.argb((int) (dimAmount
                * mBlurAnimator.currentValue() / mBlurKeyframes), 0, 0, 0));
        mColorOverlay.draw(mMMatrix); // don't need any perspective or anything for color overlay

        if (stillAnimating) {
            mCallbacks.requestRender();
        }
    }

    public void setNormalOffsetX(float x) {
        mNormalOffsetX = MathUtil.constrain(0, 1, x);
        onViewportChanged();
    }

    private void onViewportChanged() {
        mCurrentGLPictureSet.recomputeTransformMatrices();
        mNextGLPictureSet.recomputeTransformMatrices();
        if (mSurfaceCreated) {
            mCallbacks.requestRender();
        }
    }

    private float blurRadiusAtFrame(float f) {
        return mMaxPrescaledBlurPixels * mBlurInterpolator.getInterpolation(f / mBlurKeyframes);
    }

    public void setAndConsumeBitmapRegionLoader(final BitmapRegionLoader bitmapRegionLoader) {
        if (!mSurfaceCreated) {
            mQueuedNextBitmapRegionLoader = bitmapRegionLoader;
            return;
        }

        if (mCrossfadeAnimator.isRunning()) {
            if (mQueuedNextBitmapRegionLoader != null) {
                mQueuedNextBitmapRegionLoader.destroy();
            }
            mQueuedNextBitmapRegionLoader = bitmapRegionLoader;
            return;
        }

        if (!mDemoMode && !mPreview) {
            EventBus.getDefault().postSticky(new SwitchingPhotosStateChangedEvent(
                    mNextGLPictureSet.mId, true));
            EventBus.getDefault().postSticky(new ArtworkSizeChangedEvent(
                    bitmapRegionLoader.getWidth(), bitmapRegionLoader.getHeight()));
            ArtDetailViewport.getInstance().setDefaultViewport(mNextGLPictureSet.mId,
                    bitmapRegionLoader.getWidth() * 1f / bitmapRegionLoader.getHeight(),
                    mAspectRatio);
        }

        mNextGLPictureSet.load(bitmapRegionLoader);

        mCrossfadeAnimator
                .from(0).to(1)
                .withDuration(CROSSFADE_ANIMATION_DURATION)
                .withEndListener(new Runnable() {
                    @Override
                    public void run() {
                        // swap current and next picturesets
                        final GLPictureSet oldGLPictureSet = mCurrentGLPictureSet;
                        mCurrentGLPictureSet = mNextGLPictureSet;
                        mNextGLPictureSet = new GLPictureSet(oldGLPictureSet.mId);
                        mCallbacks.requestRender();
                        oldGLPictureSet.destroyPictures();
                        if (!mDemoMode) {
                            EventBus.getDefault().postSticky(new SwitchingPhotosStateChangedEvent(
                                    mCurrentGLPictureSet.mId, false));
                        }
                        System.gc();
                        if (mQueuedNextBitmapRegionLoader != null) {
                            BitmapRegionLoader queuedNextBitmapRegionLoader
                                    = mQueuedNextBitmapRegionLoader;
                            mQueuedNextBitmapRegionLoader = null;
                            setAndConsumeBitmapRegionLoader(queuedNextBitmapRegionLoader);
                        }
                    }
                })
                .start();
        mCallbacks.requestRender();
    }

    public void setDemoMode(boolean demoMode) {
        mDemoMode = demoMode;
        recomputeGreyAmount();
    }
    public void setIsPreview(boolean preview) {
        mPreview = preview;
    }

    private class GLPictureSet {
        private int mId;
        private volatile float[] mPMatrix = new float[16];
        private final float[] mMVPMatrix = new float[16];
        private GLPicture[] mPictures = new GLPicture[mBlurKeyframes + 1];
        private boolean mHasBitmap = false;
        private float mBitmapAspectRatio = 1f;
        private int mDimAmount = 0;

        public GLPictureSet(int id) {
            mId = id;
        }

        public void load(BitmapRegionLoader bitmapRegionLoader) {
            mHasBitmap = (bitmapRegionLoader != null);
            mBitmapAspectRatio = mHasBitmap
                    ? bitmapRegionLoader.getWidth() * 1f / bitmapRegionLoader.getHeight()
                    : 1f;

            mDimAmount = DEFAULT_MAX_DIM;

            destroyPictures();

            if (bitmapRegionLoader != null) {
                BitmapFactory.Options options = new BitmapFactory.Options();
                Rect rect = new Rect();
                int originalWidth = bitmapRegionLoader.getWidth();
                int originalHeight = bitmapRegionLoader.getHeight();

                // Calculate image darkness to determine dim amount
                rect.set(0, 0, originalWidth, originalHeight);
                options.inSampleSize = ImageUtil.calculateSampleSize(originalHeight, 64);
                Bitmap tempBitmap = bitmapRegionLoader.decodeRegion(rect, options);
                float darkness = ImageUtil.calculateDarkness(tempBitmap);
                mDimAmount = mDemoMode
                        ? DEMO_DIM
                        : (int) (mMaxDim * ((1 - DIM_RANGE) + DIM_RANGE * Math.sqrt(darkness)));
                if (tempBitmap != null) {
                    tempBitmap.recycle();
                }

                // Create the GLPicture objects
                mPictures[0] = new GLPicture(bitmapRegionLoader, mHeight);
                if (mMaxPrescaledBlurPixels == 0 && mMaxGrey == 0) {
                    for (int f = 1; f <= mBlurKeyframes; f++) {
                        mPictures[f] = mPictures[0];
                    }
                } else {
                    ImageBlurrer blurrer = new ImageBlurrer(mContext);
                    int sampleSizeTargetHeight, scaledHeight, scaledWidth;
                    if (mMaxPrescaledBlurPixels > 0) {
                        sampleSizeTargetHeight = mHeight / mBlurredSampleSize;
                    } else {
                        sampleSizeTargetHeight = mHeight;
                    }

                    // Note that image width should be a multiple of 4 to avoid
                    // issues with RenderScript allocations.
                    scaledHeight = Math.max(2, MathUtil.floorEven(
                            sampleSizeTargetHeight));
                    scaledWidth = Math.max(4, MathUtil.roundMult4(
                            (int) (scaledHeight * mBitmapAspectRatio)));

                    // To blur, first load the entire bitmap region, but at a very large
                    // sample size that's appropriate for the final blurred image
                    options.inSampleSize = ImageUtil.calculateSampleSize(
                            originalHeight, sampleSizeTargetHeight);
                    rect.set(0, 0, originalWidth, originalHeight);
                    tempBitmap = bitmapRegionLoader.decodeRegion(rect, options);

                    if (tempBitmap != null) {
                        // Next, create a scaled down version of the bitmap so that the blur radius
                        // looks appropriate (tempBitmap will likely be bigger than the final
                        // blurred bitmap, and thus the blur may look smaller if we just used
                        // tempBitmap as the final blurred bitmap).

                        // Note that image width should be a multiple of 4 to avoid
                        // issues with RenderScript allocations.
                        Bitmap scaledBitmap = Bitmap.createScaledBitmap(
                                tempBitmap, scaledWidth, scaledHeight, true);

                        tempBitmap.recycle();

                        // And finally, create a blurred copy for each keyframe.
                        for (int f = 1; f <= mBlurKeyframes; f++) {
                            float desaturateAmount = mMaxGrey / 500f * f / mBlurKeyframes;
                            float blurRadius = 0f;
                            if (mMaxPrescaledBlurPixels > 0) {
                                blurRadius = blurRadiusAtFrame(f);
                            }
                            Bitmap blurredBitmap = blurrer.blurBitmap(
                                    scaledBitmap, blurRadius, desaturateAmount);
                            mPictures[f] = new GLPicture(blurredBitmap);
                            if (blurredBitmap != null) {
                                blurredBitmap.recycle();
                            }
                        }

                        scaledBitmap.recycle();
                        blurrer.destroy();
                    } else {
                        LOGE(TAG, "BitmapRegionLoader failed to decode the region, rect="
                                + rect.toShortString());
                        for (int f = 1; f <= mBlurKeyframes; f++) {
                            mPictures[f] = null;
                        }
                    }
                }
            }

            recomputeTransformMatrices();
            mCallbacks.requestRender();
        }

        private void recomputeTransformMatrices() {
            float screenToBitmapAspectRatio = mAspectRatio / mBitmapAspectRatio;
            if (screenToBitmapAspectRatio == 0) {
                return;
            }

            // Ensure the bitmap is wider than the screen relatively by applying zoom
            // if necessary. Vary width but keep height the same.
            float zoom = Math.max(1f, 1.15f * screenToBitmapAspectRatio);

            // Total scale factors in both zoom and scale due to aspect ratio.
            float scaledBitmapToScreenAspectRatio = zoom / screenToBitmapAspectRatio;

            // At most pan across 1.8 screenfuls (2 screenfuls + some parallax)
            // TODO: if we know the number of home screen pages, use that number here
            float maxPanScreenWidths = Math.min(1.8f, scaledBitmapToScreenAspectRatio);

            mCurrentViewport.left = MathUtil.interpolate(-1f, 1f,
                    MathUtil.interpolate(
                            (1 - maxPanScreenWidths / scaledBitmapToScreenAspectRatio) / 2,
                            (1 + (maxPanScreenWidths - 2) / scaledBitmapToScreenAspectRatio) / 2,
                            mNormalOffsetX));
            mCurrentViewport.right = mCurrentViewport.left + 2f / scaledBitmapToScreenAspectRatio;
            mCurrentViewport.bottom = -1f / zoom;
            mCurrentViewport.top = 1f / zoom;

            float focusAmount = (mBlurKeyframes - mBlurAnimator.currentValue()) / mBlurKeyframes;
            if (mBlurRelatedToArtDetailMode && focusAmount > 0) {
                RectF artDetailViewport = ArtDetailViewport.getInstance().getViewport(mId);
                if (artDetailViewport.width() == 0 || artDetailViewport.height() == 0) {
                    if (!mDemoMode && !mPreview) {
                        // reset art detail viewport
                        ArtDetailViewport.getInstance().setViewport(mId,
                                MathUtil.uninterpolate(-1, 1, mCurrentViewport.left),
                                MathUtil.uninterpolate(1, -1, mCurrentViewport.top),
                                MathUtil.uninterpolate(-1, 1, mCurrentViewport.right),
                                MathUtil.uninterpolate(1, -1, mCurrentViewport.bottom),
                                false);
                    }
                } else {
                    // interpolate
                    mCurrentViewport.left = MathUtil.interpolate(
                            mCurrentViewport.left,
                            MathUtil.interpolate(-1, 1, artDetailViewport.left),
                            focusAmount);
                    mCurrentViewport.top = MathUtil.interpolate(
                            mCurrentViewport.top,
                            MathUtil.interpolate(1, -1, artDetailViewport.top),
                            focusAmount);
                    mCurrentViewport.right = MathUtil.interpolate(
                            mCurrentViewport.right,
                            MathUtil.interpolate(-1, 1, artDetailViewport.right),
                            focusAmount);
                    mCurrentViewport.bottom = MathUtil.interpolate(
                            mCurrentViewport.bottom,
                            MathUtil.interpolate(1, -1, artDetailViewport.bottom),
                            focusAmount);
                }
            }

            Matrix.orthoM(mPMatrix, 0,
                    mCurrentViewport.left, mCurrentViewport.right,
                    mCurrentViewport.bottom, mCurrentViewport.top,
                    1, 10);
        }

        public void drawFrame(float globalAlpha) {
            if (!mHasBitmap) {
                return;
            }

            Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
            Matrix.multiplyMM(mMVPMatrix, 0, mPMatrix, 0, mMVPMatrix, 0);

            float blurFrame = mBlurAnimator.currentValue();
            int lo = (int) Math.floor(blurFrame);
            int hi = (int) Math.ceil(blurFrame);

            float localHiAlpha = (blurFrame - lo);
            if (globalAlpha <= 0) {
                // Nothing to draw
            } else if (lo == hi) {
                // Just draw one
                if (mPictures[lo] == null) {
                    return;
                }

                mPictures[lo].draw(mMVPMatrix, globalAlpha);
            } else if (globalAlpha == 1) {
                // Simple drawing
                if (mPictures[lo] == null || mPictures[hi] == null) {
                    return;
                }

                mPictures[lo].draw(mMVPMatrix, 1);
                mPictures[hi].draw(mMVPMatrix, localHiAlpha);
            } else {
                // If there's both a global and local alpha, re-compose alphas, to
                // effectively compose hi and lo before composing the result
                // with the background.
                //
                // The math, where a1,a2 are previous alphas and b1,b2 are new alphas:
                //   b1 = a1 * (a2 - 1) / (a1 * a2 - 1)
                //   b2 = a1 * a2
                if (mPictures[lo] == null || mPictures[hi] == null) {
                    return;
                }

                float newLocalLoAlpha = globalAlpha * (localHiAlpha - 1)
                        / (globalAlpha * localHiAlpha - 1);
                float newLocalHiAlpha = globalAlpha * localHiAlpha;
                mPictures[lo].draw(mMVPMatrix, newLocalLoAlpha);
                mPictures[hi].draw(mMVPMatrix, newLocalHiAlpha);
            }
        }

        public void destroyPictures() {
            for (int i = 0; i < mPictures.length; i++) {
                if (mPictures[i] == null) {
                    continue;
                }

                mPictures[i].destroy();
                mPictures[i] = null;
            }
        }
    }

    public void destroy() {
        mCurrentGLPictureSet.destroyPictures();
        mNextGLPictureSet.destroyPictures();
    }

    public boolean isBlurred() {
        return mIsBlurred;
    }

    public void setIsBlurred(final boolean isBlurred, final boolean artDetailMode) {
        if (artDetailMode && !isBlurred && !mDemoMode && !mPreview) {
            // Reset art detail viewport
            ArtDetailViewport.getInstance().setViewport(0, 0, 0, 0, 0, false);
            ArtDetailViewport.getInstance().setViewport(1, 0, 0, 0, 0, false);
        }

        mBlurRelatedToArtDetailMode = artDetailMode;
        mIsBlurred = isBlurred;
        mBlurAnimator.cancel();
        mBlurAnimator
                .to(isBlurred ? mBlurKeyframes : 0)
                .withDuration(BLUR_ANIMATION_DURATION * (mDemoMode ? 5 : 1))
                .withEndListener(new Runnable() {
                    @Override
                    public void run() {
                        if (isBlurred && artDetailMode) {
                            System.gc();
                        }
                    }
                })
                .start();
        mCallbacks.requestRender();
    }

    public static interface Callbacks {
        void requestRender();
    }
}




Java Source Code List

com.example.muzei.examplecontractwidget.ArtworkUpdateReceiver.java
com.example.muzei.examplecontractwidget.ArtworkUpdateService.java
com.example.muzei.examplecontractwidget.MuzeiAppWidgetProvider.java
com.example.muzei.examplesource500px.Config.java
com.example.muzei.examplesource500px.FiveHundredPxExampleArtSource.java
com.example.muzei.examplesource500px.FiveHundredPxService.java
com.example.muzei.watchface.ArtworkImageLoader.java
com.example.muzei.watchface.MuzeiExampleWatchface.java
com.example.muzei.watchface.WatchfaceArtworkImageLoader.java
com.google.android.apps.muzei.ActivateMuzeiIntentService.java
com.google.android.apps.muzei.ArtDetailViewport.java
com.google.android.apps.muzei.ArtworkCacheIntentService.java
com.google.android.apps.muzei.ArtworkCache.java
com.google.android.apps.muzei.FullScreenActivity.java
com.google.android.apps.muzei.LockScreenVisibleReceiver.java
com.google.android.apps.muzei.MuzeiActivity.java
com.google.android.apps.muzei.MuzeiApplication.java
com.google.android.apps.muzei.MuzeiWallpaperService.java
com.google.android.apps.muzei.MuzeiWatchFace.java
com.google.android.apps.muzei.MuzeiWearableListenerService.java
com.google.android.apps.muzei.MuzeiWearableListenerService.java
com.google.android.apps.muzei.NetworkChangeReceiver.java
com.google.android.apps.muzei.NewWallpaperNotificationReceiver.java
com.google.android.apps.muzei.PhotoSetAsTargetActivity.java
com.google.android.apps.muzei.SourceManager.java
com.google.android.apps.muzei.SourcePackageChangeReceiver.java
com.google.android.apps.muzei.SourceSubscriberService.java
com.google.android.apps.muzei.TaskQueueService.java
com.google.android.apps.muzei.WearableController.java
com.google.android.apps.muzei.api.Artwork.java
com.google.android.apps.muzei.api.MuzeiArtSource.java
com.google.android.apps.muzei.api.MuzeiContract.java
com.google.android.apps.muzei.api.RemoteMuzeiArtSource.java
com.google.android.apps.muzei.api.UserCommand.java
com.google.android.apps.muzei.api.internal.ProtocolConstants.java
com.google.android.apps.muzei.api.internal.SourceState.java
com.google.android.apps.muzei.event.ArtDetailOpenedClosedEvent.java
com.google.android.apps.muzei.event.ArtworkLoadingStateChangedEvent.java
com.google.android.apps.muzei.event.ArtworkSizeChangedEvent.java
com.google.android.apps.muzei.event.BlurAmountChangedEvent.java
com.google.android.apps.muzei.event.CurrentArtworkDownloadedEvent.java
com.google.android.apps.muzei.event.DimAmountChangedEvent.java
com.google.android.apps.muzei.event.GainedNetworkConnectivityEvent.java
com.google.android.apps.muzei.event.GalleryChosenUrisChangedEvent.java
com.google.android.apps.muzei.event.GreyAmountChangedEvent.java
com.google.android.apps.muzei.event.LockScreenVisibleChangedEvent.java
com.google.android.apps.muzei.event.SelectedSourceChangedEvent.java
com.google.android.apps.muzei.event.SelectedSourceStateChangedEvent.java
com.google.android.apps.muzei.event.SwitchingPhotosStateChangedEvent.java
com.google.android.apps.muzei.event.WallpaperActiveStateChangedEvent.java
com.google.android.apps.muzei.event.WallpaperSizeChangedEvent.java
com.google.android.apps.muzei.featuredart.FeaturedArtSource.java
com.google.android.apps.muzei.gallery.GalleryArtSource.java
com.google.android.apps.muzei.gallery.GalleryDatabase.java
com.google.android.apps.muzei.gallery.GalleryEmptyStateGraphicView.java
com.google.android.apps.muzei.gallery.GallerySettingsActivity.java
com.google.android.apps.muzei.gallery.GalleryStore.java
com.google.android.apps.muzei.provider.MuzeiProvider.java
com.google.android.apps.muzei.render.BitmapRegionLoader.java
com.google.android.apps.muzei.render.DemoRenderController.java
com.google.android.apps.muzei.render.GLColorOverlay.java
com.google.android.apps.muzei.render.GLPicture.java
com.google.android.apps.muzei.render.GLTextureView.java
com.google.android.apps.muzei.render.GLUtil.java
com.google.android.apps.muzei.render.ImageUtil.java
com.google.android.apps.muzei.render.MuzeiBlurRenderer.java
com.google.android.apps.muzei.render.MuzeiRendererFragment.java
com.google.android.apps.muzei.render.RealRenderController.java
com.google.android.apps.muzei.render.RenderController.java
com.google.android.apps.muzei.settings.AboutActivity.java
com.google.android.apps.muzei.settings.Prefs.java
com.google.android.apps.muzei.settings.SettingsActivity.java
com.google.android.apps.muzei.settings.SettingsAdvancedFragment.java
com.google.android.apps.muzei.settings.SettingsChooseSourceFragment.java
com.google.android.apps.muzei.util.AnimatedMuzeiLoadingSpinnerView.java
com.google.android.apps.muzei.util.AnimatedMuzeiLogoFragment.java
com.google.android.apps.muzei.util.AnimatedMuzeiLogoView.java
com.google.android.apps.muzei.util.CheatSheet.java
com.google.android.apps.muzei.util.DrawInsetsFrameLayout.java
com.google.android.apps.muzei.util.IOUtil.java
com.google.android.apps.muzei.util.ImageBlurrer.java
com.google.android.apps.muzei.util.LogUtil.java
com.google.android.apps.muzei.util.LogoPaths.java
com.google.android.apps.muzei.util.MathUtil.java
com.google.android.apps.muzei.util.MultiSelectionController.java
com.google.android.apps.muzei.util.ObservableHorizontalScrollView.java
com.google.android.apps.muzei.util.PanScaleProxyView.java
com.google.android.apps.muzei.util.PanView.java
com.google.android.apps.muzei.util.ScrimUtil.java
com.google.android.apps.muzei.util.Scrollbar.java
com.google.android.apps.muzei.util.SelectionBuilder.java
com.google.android.apps.muzei.util.ShadowDipsTextView.java
com.google.android.apps.muzei.util.SvgPathParser.java
com.google.android.apps.muzei.util.TickingFloatAnimator.java
com.google.android.apps.muzei.util.TypefaceUtil.java
com.google.android.apps.muzei.util.Zoomer.java
net.rbgrn.android.glwallpaperservice.BaseConfigChooser.java
net.rbgrn.android.glwallpaperservice.GLWallpaperService.java