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;
39ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupinimport android.app.WallpaperColors;
40e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roosimport android.util.Log;
41e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
42d11d1a9486d44b98e28b70c25711ebfc283b746eJorim Jaggiimport com.android.keyguard.KeyguardUpdateMonitor;
43d11d1a9486d44b98e28b70c25711ebfc283b746eJorim Jaggi
44e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roosimport libcore.io.IoUtils;
45e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
4612a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshevimport java.util.Objects;
4712a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev
48e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos/**
49e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos * Manages the lockscreen wallpaper.
50e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos */
51e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roospublic class LockscreenWallpaper extends IWallpaperManagerCallback.Stub implements Runnable {
52e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
53e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    private static final String TAG = "LockscreenWallpaper";
54e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
552a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk    private final StatusBar mBar;
5612a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev    private final WallpaperManager mWallpaperManager;
57e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    private final Handler mH;
58d11d1a9486d44b98e28b70c25711ebfc283b746eJorim Jaggi    private final KeyguardUpdateMonitor mUpdateMonitor;
59e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
60e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    private boolean mCached;
61e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    private Bitmap mCache;
6212a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev    private int mCurrentUserId;
6312a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev    // The user selected in the UI, or null if no user is selected or UI doesn't support selecting
6412a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev    // users.
6512a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev    private UserHandle mSelectedUser;
667e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos    private AsyncTask<Void, Void, LoaderResult> mLoader;
67e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
682a6ea9c2a1b52b0386270ec73e1e6d6a9b614a34Jason Monk    public LockscreenWallpaper(Context ctx, StatusBar bar, Handler h) {
69e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        mBar = bar;
70e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        mH = h;
7112a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev        mWallpaperManager = (WallpaperManager) ctx.getSystemService(Context.WALLPAPER_SERVICE);
7212a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev        mCurrentUserId = ActivityManager.getCurrentUser();
73d11d1a9486d44b98e28b70c25711ebfc283b746eJorim Jaggi        mUpdateMonitor = KeyguardUpdateMonitor.getInstance(ctx);
74e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
757e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        IWallpaperManager service = IWallpaperManager.Stub.asInterface(
767e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                ServiceManager.getService(Context.WALLPAPER_SERVICE));
77e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        try {
787e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            service.setLockWallpaperCallback(this);
79e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        } catch (RemoteException e) {
80e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos            Log.e(TAG, "System dead?" + e);
81e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        }
82e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    }
83e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
84e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    public Bitmap getBitmap() {
857e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        if (mCached) {
867e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            return mCache;
877e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        }
887e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        if (!mWallpaperManager.isWallpaperSupported()) {
897e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            mCached = true;
907e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            mCache = null;
917e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            return null;
927e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        }
937e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
947e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        LoaderResult result = loadBitmap(mCurrentUserId, mSelectedUser);
957e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        if (result.success) {
967e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            mCached = true;
97d11d1a9486d44b98e28b70c25711ebfc283b746eJorim Jaggi            mUpdateMonitor.setHasLockscreenWallpaper(result.bitmap != null);
987e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            mCache = result.bitmap;
997e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        }
1007e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        return mCache;
1017e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos    }
1027e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
1037e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos    public LoaderResult loadBitmap(int currentUserId, UserHandle selectedUser) {
1047e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        // May be called on any thread - only use thread safe operations.
1057e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
1067e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        // Prefer the selected user (when specified) over the current user for the FLAG_SET_LOCK
1077e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        // wallpaper.
1087e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        final int lockWallpaperUserId =
1097e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                selectedUser != null ? selectedUser.getIdentifier() : currentUserId;
1107e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        ParcelFileDescriptor fd = mWallpaperManager.getWallpaperFile(
1117e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                WallpaperManager.FLAG_LOCK, lockWallpaperUserId);
1127e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
1137e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        if (fd != null) {
1147e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            try {
1157e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                BitmapFactory.Options options = new BitmapFactory.Options();
1167e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                return LoaderResult.success(BitmapFactory.decodeFileDescriptor(
1177e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                        fd.getFileDescriptor(), null, options));
1187e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            } catch (OutOfMemoryError e) {
1197e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                Log.w(TAG, "Can't decode file", e);
1207e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                return LoaderResult.fail();
1217e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            } finally {
1227e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                IoUtils.closeQuietly(fd);
123e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos            }
1247e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        } else {
1254324f9f2476afc08e41700faa23ee33881d0d3b8Evan Rosky            if (selectedUser != null) {
1264324f9f2476afc08e41700faa23ee33881d0d3b8Evan Rosky                // Show the selected user's static wallpaper.
127049978e61d99ad68e3acac16f0f3801d1eeedad6Lucas Dupin                return LoaderResult.success(mWallpaperManager.getBitmapAsUser(
128049978e61d99ad68e3acac16f0f3801d1eeedad6Lucas Dupin                        selectedUser.getIdentifier(), true /* hardware */));
1297e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
130e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos            } else {
1314324f9f2476afc08e41700faa23ee33881d0d3b8Evan Rosky                // When there is no selected user, show the system wallpaper
1327e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                return LoaderResult.success(null);
133e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos            }
134e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        }
135e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    }
136e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
13712a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev    public void setCurrentUser(int user) {
13812a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev        if (user != mCurrentUserId) {
13913a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky            if (mSelectedUser == null || user != mSelectedUser.getIdentifier()) {
14013a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky                mCached = false;
14113a58a91d362e74933b3064a65be4bf4449cfdc4Evan Rosky            }
14212a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev            mCurrentUserId = user;
143e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        }
144e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    }
145e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
14612a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev    public void setSelectedUser(UserHandle selectedUser) {
14712a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev        if (Objects.equals(selectedUser, mSelectedUser)) {
14812a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev            return;
14912a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev        }
15012a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev        mSelectedUser = selectedUser;
1517e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        postUpdateWallpaper();
15212a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev    }
15312a30e8874cedbc7f0cc3a7ec6821bc42de3280eVadim Tryshev
154e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    @Override
155e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    public void onWallpaperChanged() {
156e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        // Called on Binder thread.
1577e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        postUpdateWallpaper();
1587e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos    }
1597e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
160ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin    @Override
16150ba991655555dfde90149489f6485a0529ba0acLucas Dupin    public void onWallpaperColorsChanged(WallpaperColors colors, int which, int userId) {
162ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin
163ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin    }
164ea1fb1e077e9fa8ce6a8a9e8caaf7423dc09cc9dLucas Dupin
1657e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos    private void postUpdateWallpaper() {
166e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        mH.removeCallbacks(this);
167e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        mH.post(this);
168e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    }
169e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos
170e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    @Override
171e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    public void run() {
172e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos        // Called in response to onWallpaperChanged on the main thread.
1737e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
1747e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        if (mLoader != null) {
1757e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            mLoader.cancel(false /* interrupt */);
1767e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        }
1777e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
1787e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        final int currentUser = mCurrentUserId;
1797e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        final UserHandle selectedUser = mSelectedUser;
1807e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        mLoader = new AsyncTask<Void, Void, LoaderResult>() {
1817e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            @Override
1827e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            protected LoaderResult doInBackground(Void... params) {
1837e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                return loadBitmap(currentUser, selectedUser);
1847e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            }
1857e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
1867e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            @Override
1877e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            protected void onPostExecute(LoaderResult result) {
1887e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                super.onPostExecute(result);
1897e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                if (isCancelled()) {
1907e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                    return;
1917e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                }
1927e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                if (result.success) {
1937e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                    mCached = true;
1947e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                    mCache = result.bitmap;
195d11d1a9486d44b98e28b70c25711ebfc283b746eJorim Jaggi                    mUpdateMonitor.setHasLockscreenWallpaper(result.bitmap != null);
1967e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                    mBar.updateMediaMetaData(
1977e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                            true /* metaDataChanged */, true /* allowEnterAnimation */);
1987e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                }
1997e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos                mLoader = null;
2007e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            }
2017e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
2027e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos    }
2037e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
2047e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos    private static class LoaderResult {
2057e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        public final boolean success;
2067e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        public final Bitmap bitmap;
2077e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
2087e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        LoaderResult(boolean success, Bitmap bitmap) {
2097e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            this.success = success;
2107e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            this.bitmap = bitmap;
2117e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        }
2127e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
2137e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        static LoaderResult success(Bitmap b) {
2147e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            return new LoaderResult(true, b);
2157e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        }
2167e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos
2177e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        static LoaderResult fail() {
2187e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos            return new LoaderResult(false, null);
2197e9dec284128ef07024c85bc59f317f3e6726c23Adrian Roos        }
220e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos    }
2213b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2223b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos    /**
2233b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos     * Drawable that aligns left horizontally and center vertically (like ImageWallpaper).
2243b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos     */
2253b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos    public static class WallpaperDrawable extends DrawableWrapper {
2263b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
227751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        private final ConstantState mState;
228751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        private final Rect mTmpRect = new Rect();
2293b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2303b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        public WallpaperDrawable(Resources r, Bitmap b) {
231751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            this(r, new ConstantState(b));
232751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        }
233751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos
234751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        private WallpaperDrawable(Resources r, ConstantState state) {
235751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            super(new BitmapDrawable(r, state.mBackground));
236751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            mState = state;
2373b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        }
2383b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2393b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        @Override
240d866b02d5435108db41c8f4a68175c52ca319c55Adrian Roos        public void setXfermode(@Nullable Xfermode mode) {
241d866b02d5435108db41c8f4a68175c52ca319c55Adrian Roos            // DrawableWrapper does not call this for us.
242d866b02d5435108db41c8f4a68175c52ca319c55Adrian Roos            getDrawable().setXfermode(mode);
243d866b02d5435108db41c8f4a68175c52ca319c55Adrian Roos        }
244d866b02d5435108db41c8f4a68175c52ca319c55Adrian Roos
245d866b02d5435108db41c8f4a68175c52ca319c55Adrian Roos        @Override
2463b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        public int getIntrinsicWidth() {
2473b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            return -1;
2483b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        }
2493b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2503b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        @Override
2513b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        public int getIntrinsicHeight() {
2523b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            return -1;
2533b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        }
2543b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2553b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        @Override
2563b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        protected void onBoundsChange(Rect bounds) {
2573b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            int vwidth = getBounds().width();
2583b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            int vheight = getBounds().height();
259751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            int dwidth = mState.mBackground.getWidth();
260751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            int dheight = mState.mBackground.getHeight();
2613b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            float scale;
2623b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            float dx = 0, dy = 0;
2633b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2643b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            if (dwidth * vheight > vwidth * dheight) {
2653b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos                scale = (float) vheight / (float) dheight;
2663b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            } else {
2673b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos                scale = (float) vwidth / (float) dwidth;
2683b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            }
2693b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2703b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            if (scale <= 1f) {
2713b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos                scale = 1f;
2723b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            }
2733b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            dy = (vheight - dheight * scale) * 0.5f;
2743b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2753b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            mTmpRect.set(
2763b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos                    bounds.left,
2773b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos                    bounds.top + Math.round(dy),
2783b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos                    bounds.left + Math.round(dwidth * scale),
2793b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos                    bounds.top + Math.round(dheight * scale + dy));
2803b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos
2813b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos            super.onBoundsChange(mTmpRect);
2823b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos        }
283751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos
284751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        @Override
285751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        public ConstantState getConstantState() {
286751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            return mState;
287751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        }
288751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos
289751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        static class ConstantState extends Drawable.ConstantState {
290751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos
291751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            private final Bitmap mBackground;
292751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos
293751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            ConstantState(Bitmap background) {
294751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos                mBackground = background;
295751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            }
296751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos
297751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            @Override
298751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            public Drawable newDrawable() {
299751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos                return newDrawable(null);
300751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            }
301751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos
302751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            @Override
303751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            public Drawable newDrawable(@Nullable Resources res) {
304751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos                return new WallpaperDrawable(res, this);
305751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            }
306751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos
307751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            @Override
308751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            public int getChangingConfigurations() {
309751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos                // DrawableWrapper already handles this for us.
310751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos                return 0;
311751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos            }
312751f33f8c73892a34f99eb0f4c8266b87a331283Adrian Roos        }
3133b777cb9b18c3e6f8549cd25695600cd7dd3010bAdrian Roos    }
314e381c169fc445b961a131ea5553150d4c44f0c9eAdrian Roos}
315