1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.wallpaper.asset;
17 
18 import android.app.Activity;
19 import android.app.WallpaperManager;
20 import android.content.Context;
21 import android.graphics.Bitmap;
22 import android.graphics.Point;
23 import android.graphics.Rect;
24 import android.graphics.drawable.BitmapDrawable;
25 import android.graphics.drawable.Drawable;
26 import android.os.AsyncTask;
27 
28 /**
29  * Asset implementation which represents the currently-set wallpaper on API 16 through 23 devices.
30  */
31 public class CurrentWallpaperAssetV16 extends Asset {
32 
33     private static final boolean FILTER_SCALED_BITMAP = true;
34 
35     private Context mApplicationContext;
36     private Drawable mCurrentWallpaperDrawable;
37 
CurrentWallpaperAssetV16(Context context)38     public CurrentWallpaperAssetV16(Context context) {
39         mApplicationContext = context.getApplicationContext();
40     }
41 
42     @Override
decodeBitmapRegion(Rect rect, int targetWidth, int targetHeight, boolean shouldAdjustForRtl, BitmapReceiver receiver)43     public void decodeBitmapRegion(Rect rect, int targetWidth, int targetHeight,
44             boolean shouldAdjustForRtl, BitmapReceiver receiver) {
45         receiver.onBitmapDecoded(null);
46     }
47 
48     @Override
decodeBitmap(int targetWidth, int targetHeight, BitmapReceiver receiver)49     public void decodeBitmap(int targetWidth, int targetHeight,
50                              BitmapReceiver receiver) {
51         DecodeBitmapAsyncTask task = new DecodeBitmapAsyncTask(receiver, targetWidth, targetHeight);
52         task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
53     }
54 
55     @Override
supportsTiling()56     public boolean supportsTiling() {
57         return false;
58     }
59 
60     @Override
decodeRawDimensions(Activity unused, DimensionsReceiver receiver)61     public void decodeRawDimensions(Activity unused, DimensionsReceiver receiver) {
62         DecodeDimensionsAsyncTask task = new DecodeDimensionsAsyncTask(receiver);
63         task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
64     }
65 
getCurrentWallpaperDrawable()66     private synchronized Drawable getCurrentWallpaperDrawable() {
67         if (mCurrentWallpaperDrawable != null) {
68             return mCurrentWallpaperDrawable;
69         }
70         WallpaperManager wallpaperManager = WallpaperManager.getInstance(mApplicationContext);
71         try {
72             mCurrentWallpaperDrawable = wallpaperManager.getDrawable();
73         } catch (java.lang.SecurityException e) {
74             // Work around Samsung bug where SecurityException is thrown if device is still using
75             // its default wallpaper.
76             mCurrentWallpaperDrawable = wallpaperManager.getBuiltInDrawable();
77         }
78         return mCurrentWallpaperDrawable;
79     }
80 
81     /**
82      * Decodes and then post-decode scales down the currently-set wallpaper bitmap.
83      */
84     private class DecodeBitmapAsyncTask extends AsyncTask<Void, Void, Bitmap> {
85 
86         private BitmapReceiver mReceiver;
87         private int mTargetWidth;
88         private int mTargetHeight;
89 
DecodeBitmapAsyncTask(BitmapReceiver receiver, int width, int height)90         public DecodeBitmapAsyncTask(BitmapReceiver receiver, int width, int height) {
91             mReceiver = receiver;
92             mTargetWidth = width;
93             mTargetHeight = height;
94         }
95 
96         @Override
doInBackground(Void... unused)97         protected Bitmap doInBackground(Void... unused) {
98             Drawable wallpaperDrawable = getCurrentWallpaperDrawable();
99             Bitmap bitmap = ((BitmapDrawable) wallpaperDrawable).getBitmap();
100 
101             // The final bitmap may be constrained by only one of height and width, so find the maximum
102             // downscaling factor without having the final result bitmap's height or width dip below the
103             // provided target height or width.
104             float maxDownscaleFactor = Math.min((float) bitmap.getWidth() / mTargetWidth,
105                     (float) bitmap.getHeight() / mTargetHeight);
106 
107             // Scale down full bitmap to save memory consumption post-decoding, while maintaining the
108             // source bitmap's aspect ratio.
109             int resultWidth = Math.round(bitmap.getWidth() / maxDownscaleFactor);
110             int resultHeight = Math.round(bitmap.getHeight() / maxDownscaleFactor);
111             return Bitmap.createScaledBitmap(bitmap, resultWidth, resultHeight, FILTER_SCALED_BITMAP);
112         }
113 
114         @Override
onPostExecute(Bitmap bitmap)115         protected void onPostExecute(Bitmap bitmap) {
116             mReceiver.onBitmapDecoded(bitmap);
117         }
118     }
119 
120     /**
121      * Decodes the raw dimensions of the currently-set wallpaper.
122      */
123     private class DecodeDimensionsAsyncTask extends AsyncTask<Void, Void, Point> {
124 
125         private DimensionsReceiver mReceiver;
126 
DecodeDimensionsAsyncTask(DimensionsReceiver receiver)127         public DecodeDimensionsAsyncTask(DimensionsReceiver receiver) {
128             mReceiver = receiver;
129         }
130 
131         @Override
doInBackground(Void... unused)132         protected Point doInBackground(Void... unused) {
133             Drawable wallpaperDrawable = getCurrentWallpaperDrawable();
134             return new Point(
135                     wallpaperDrawable.getIntrinsicWidth(), wallpaperDrawable.getIntrinsicHeight());
136         }
137 
138         @Override
onPostExecute(Point dimensions)139         protected void onPostExecute(Point dimensions) {
140             mReceiver.onDimensionsDecoded(dimensions);
141         }
142     }
143 }
144