1e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos/*
2e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos * Copyright (C) 2016 The Android Open Source Project
3e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos *
4e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos * Licensed under the Apache License, Version 2.0 (the "License");
5e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos * you may not use this file except in compliance with the License.
6e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos * You may obtain a copy of the License at
7e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos *
8e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos *      http://www.apache.org/licenses/LICENSE-2.0
9e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos *
10e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos * Unless required by applicable law or agreed to in writing, software
11e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos * distributed under the License is distributed on an "AS IS" BASIS,
12e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos * See the License for the specific language governing permissions and
14e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos * limitations under the License
15e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos */
16e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
17e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roospackage com.android.systemui.statusbar.phone;
18e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
19751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roosimport android.annotation.Nullable;
20e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roosimport android.app.ActivityManager;
21e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roosimport android.app.IWallpaperManager;
22e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roosimport android.app.IWallpaperManagerCallback;
23e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roosimport android.app.WallpaperManager;
24e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roosimport android.content.Context;
253b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roosimport android.content.res.Resources;
26e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roosimport android.graphics.Bitmap;
27e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roosimport android.graphics.BitmapFactory;
283b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roosimport android.graphics.Rect;
29d866b02d5435108db41c8f4a68175c52ca319c55Adrian Roosimport android.graphics.Xfermode;
303b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roosimport android.graphics.drawable.BitmapDrawable;
31751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roosimport android.graphics.drawable.Drawable;
323b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roosimport android.graphics.drawable.DrawableWrapper;
337e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roosimport android.os.AsyncTask;
34e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roosimport android.os.Handler;
35e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roosimport android.os.ParcelFileDescriptor;
36e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roosimport android.os.RemoteException;
37e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roosimport android.os.ServiceManager;
3812a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshevimport android.os.UserHandle;
39e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roosimport android.util.Log;
40e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
41d11d1a9486d44b98e28b70c25711ebfc283b746eJorim Jaggiimport com.android.keyguard.KeyguardUpdateMonitor;
42d11d1a9486d44b98e28b70c25711ebfc283b746eJorim Jaggi
43e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roosimport libcore.io.IoUtils;
44e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
4512a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshevimport java.util.Objects;
4612a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev
47e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos/**
48e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos * Manages the lockscreen wallpaper.
49e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos */
50e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roospublic class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implements Runnable {
51e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
52e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    private static final String TAG = "LockscreenWallpaper";
53e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
542a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk    private final StatusBar mBar;
5512a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev    private final WallpaperManager mWallpaperManager;
56e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    private final Handler mH;
57d11d1a9486d44b98e28b70c25711ebfc283b746eJorim Jaggi    private final KeyguardUpdateMonitor mUpdateMonitor;
58e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
59e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    private boolean mCached;
60e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    private Bitmap mCache;
6112a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev    private int mCurrentUserId;
6212a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev    // The user selected in the UI, or null if no user is selected or UI doesn't support selecting
6312a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev    // users.
6412a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev    private UserHandle mSelectedUser;
657e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos    private AsyncTask<Void, Void, LoaderResult> mLoader;
66e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
672a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk    public LockscreenWallpaper(Context ctx, StatusBar bar, Handler h) {
68e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        mBar = bar;
69e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        mH = h;
7012a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev        mWallpaperManager = (WallpaperManager) ctx.getSystemService(Context.WALLPAPER_SERVICE);
7112a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev        mCurrentUserId = ActivityManager.getCurrentUser();
72d11d1a9486d44b98e28b70c25711ebfc283b746eJorim Jaggi        mUpdateMonitor = KeyguardUpdateMonitor.getInstance(ctx);
73e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
747e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        IWallpaperManager service = IWallpaperManager.Stub.asInterface(
757e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                ServiceManager.getService(Context.WALLPAPER_SERVICE));
76e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        try {
777e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            service.setLockWallpaperCallback(this);
78e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        } catch (RemoteException e) {
79e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos            Log.e(TAG, "System dead?" + e);
80e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        }
81e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    }
82e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
83e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    public Bitmap getBitmap() {
847e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        if (mCached) {
857e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            return mCache;
867e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        }
877e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        if (!mWallpaperManager.isWallpaperSupported()) {
887e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            mCached = true;
897e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            mCache = null;
907e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            return null;
917e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        }
927e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
937e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        LoaderResult result = loadBitmap(mCurrentUserId, mSelectedUser);
947e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        if (result.success) {
957e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            mCached = true;
96d11d1a9486d44b98e28b70c25711ebfc283b746eJorim Jaggi            mUpdateMonitor.setHasLockscreenWallpaper(result.bitmap != null);
977e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            mCache = result.bitmap;
987e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        }
997e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        return mCache;
1007e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos    }
1017e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
1027e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos    public LoaderResult loadBitmap(int currentUserId, UserHandle selectedUser) {
1037e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        // May be called on any thread - only use thread safe operations.
1047e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
1057e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        // Prefer the selected user (when specified) over the current user for the FLAG_SET_LOCK
1067e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        // wallpaper.
1077e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        final int lockWallpaperUserId =
1087e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                selectedUser != null ? selectedUser.getIdentifier() : currentUserId;
1097e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        ParcelFileDescriptor fd = mWallpaperManager.getWallpaperFile(
1107e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                WallpaperManager.FLAG_LOCK, lockWallpaperUserId);
1117e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
1127e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        if (fd != null) {
1137e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            try {
1147e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                BitmapFactory.Options options = new BitmapFactory.Options();
1157e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                return LoaderResult.success(BitmapFactory.decodeFileDescriptor(
1167e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                        fd.getFileDescriptor(), null, options));
1177e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            } catch (OutOfMemoryError e) {
1187e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                Log.w(TAG, "Can't decode file", e);
1197e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                return LoaderResult.fail();
1207e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            } finally {
1217e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                IoUtils.closeQuietly(fd);
122e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos            }
1237e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        } else {
1244324f9f2476afc08e41700faa23ee33881d0d3b8Evan Rosky            if (selectedUser != null) {
1254324f9f2476afc08e41700faa23ee33881d0d3b8Evan Rosky                // Show the selected user's static wallpaper.
1267e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                return LoaderResult.success(
1277e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                        mWallpaperManager.getBitmapAsUser(selectedUser.getIdentifier()));
1287e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
129e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos            } else {
1304324f9f2476afc08e41700faa23ee33881d0d3b8Evan Rosky                // When there is no selected user, show the system wallpaper
1317e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                return LoaderResult.success(null);
132e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos            }
133e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        }
134e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    }
135e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
13612a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev    public void setCurrentUser(int user) {
13712a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev        if (user != mCurrentUserId) {
13813a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky            if (mSelectedUser == null || user != mSelectedUser.getIdentifier()) {
13913a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky                mCached = false;
14013a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky            }
14112a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev            mCurrentUserId = user;
142e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        }
143e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    }
144e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
14512a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev    public void setSelectedUser(UserHandle selectedUser) {
14612a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev        if (Objects.equals(selectedUser, mSelectedUser)) {
14712a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev            return;
14812a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev        }
14912a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev        mSelectedUser = selectedUser;
1507e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        postUpdateWallpaper();
15112a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev    }
15212a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev
153e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    @Override
154e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    public void onWallpaperChanged() {
155e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        // Called on Binder thread.
1567e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        postUpdateWallpaper();
1577e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos    }
1587e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
1597e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos    private void postUpdateWallpaper() {
160e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        mH.removeCallbacks(this);
161e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        mH.post(this);
162e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    }
163e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
164e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    @Override
165e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    public void run() {
166e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        // Called in response to onWallpaperChanged on the main thread.
1677e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
1687e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        if (mLoader != null) {
1697e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            mLoader.cancel(false /* interrupt */);
1707e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        }
1717e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
1727e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        final int currentUser = mCurrentUserId;
1737e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        final UserHandle selectedUser = mSelectedUser;
1747e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        mLoader = new AsyncTask<Void, Void, LoaderResult>() {
1757e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            @Override
1767e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            protected LoaderResult doInBackground(Void... params) {
1777e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                return loadBitmap(currentUser, selectedUser);
1787e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            }
1797e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
1807e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            @Override
1817e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            protected void onPostExecute(LoaderResult result) {
1827e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                super.onPostExecute(result);
1837e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                if (isCancelled()) {
1847e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                    return;
1857e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                }
1867e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                if (result.success) {
1877e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                    mCached = true;
1887e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                    mCache = result.bitmap;
189d11d1a9486d44b98e28b70c25711ebfc283b746eJorim Jaggi                    mUpdateMonitor.setHasLockscreenWallpaper(result.bitmap != null);
1907e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                    mBar.updateMediaMetaData(
1917e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                            true /* metaDataChanged */, true /* allowEnterAnimation */);
1927e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                }
1937e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                mLoader = null;
1947e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            }
1957e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
1967e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos    }
1977e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
1987e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos    private static class LoaderResult {
1997e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        public final boolean success;
2007e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        public final Bitmap bitmap;
2017e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
2027e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        LoaderResult(boolean success, Bitmap bitmap) {
2037e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            this.success = success;
2047e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            this.bitmap = bitmap;
2057e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        }
2067e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
2077e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        static LoaderResult success(Bitmap b) {
2087e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            return new LoaderResult(true, b);
2097e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        }
2107e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
2117e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        static LoaderResult fail() {
2127e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            return new LoaderResult(false, null);
2137e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        }
214e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    }
2153b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2163b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos    /**
2173b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos     * Drawable that aligns left horizontally and center vertically (like ImageWallpaper).
2183b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos     */
2193b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos    public static class WallpaperDrawable extends DrawableWrapper {
2203b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
221751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        private final ConstantState mState;
222751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        private final Rect mTmpRect = new Rect();
2233b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2243b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        public WallpaperDrawable(Resources r, Bitmap b) {
225751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            this(r, new ConstantState(b));
226751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        }
227751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos
228751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        private WallpaperDrawable(Resources r, ConstantState state) {
229751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            super(new BitmapDrawable(r, state.mBackground));
230751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            mState = state;
2313b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        }
2323b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2333b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        @Override
234d866b02d5435108db41c8f4a68175c52ca319c55Adrian Roos        public void setXfermode(@Nullable Xfermode mode) {
235d866b02d5435108db41c8f4a68175c52ca319c55Adrian Roos            // DrawableWrapper does not call this for us.
236d866b02d5435108db41c8f4a68175c52ca319c55Adrian Roos            getDrawable().setXfermode(mode);
237d866b02d5435108db41c8f4a68175c52ca319c55Adrian Roos        }
238d866b02d5435108db41c8f4a68175c52ca319c55Adrian Roos
239d866b02d5435108db41c8f4a68175c52ca319c55Adrian Roos        @Override
2403b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        public int getIntrinsicWidth() {
2413b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            return -1;
2423b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        }
2433b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2443b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        @Override
2453b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        public int getIntrinsicHeight() {
2463b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            return -1;
2473b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        }
2483b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2493b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        @Override
2503b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        protected void onBoundsChange(Rect bounds) {
2513b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            int vwidth = getBounds().width();
2523b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            int vheight = getBounds().height();
253751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            int dwidth = mState.mBackground.getWidth();
254751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            int dheight = mState.mBackground.getHeight();
2553b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            float scale;
2563b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            float dx = 0, dy = 0;
2573b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2583b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            if (dwidth * vheight > vwidth * dheight) {
2593b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos                scale = (float) vheight / (float) dheight;
2603b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            } else {
2613b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos                scale = (float) vwidth / (float) dwidth;
2623b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            }
2633b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2643b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            if (scale <= 1f) {
2653b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos                scale = 1f;
2663b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            }
2673b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            dy = (vheight - dheight * scale) * 0.5f;
2683b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2693b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            mTmpRect.set(
2703b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos                    bounds.left,
2713b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos                    bounds.top + Math.round(dy),
2723b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos                    bounds.left + Math.round(dwidth * scale),
2733b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos                    bounds.top + Math.round(dheight * scale + dy));
2743b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2753b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            super.onBoundsChange(mTmpRect);
2763b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        }
277751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos
278751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        @Override
279751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        public ConstantState getConstantState() {
280751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            return mState;
281751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        }
282751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos
283751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        static class ConstantState extends Drawable.ConstantState {
284751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos
285751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            private final Bitmap mBackground;
286751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos
287751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            ConstantState(Bitmap background) {
288751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos                mBackground = background;
289751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            }
290751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos
291751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            @Override
292751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            public Drawable newDrawable() {
293751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos                return newDrawable(null);
294751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            }
295751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos
296751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            @Override
297751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            public Drawable newDrawable(@Nullable Resources res) {
298751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos                return new WallpaperDrawable(res, this);
299751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            }
300751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos
301751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            @Override
302751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            public int getChangingConfigurations() {
303751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos                // DrawableWrapper already handles this for us.
304751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos                return 0;
305751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            }
306751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        }
3073b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos    }
308e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos}
309